18

I am creating a website of floating width. The users use screens from full HD resolution to some 600px on smart phones it seems a pretty good idea. This brings up a very interesting problem.

When user uses a smaller resolution than is an optimum the page gets a lot more height. This means it might be useful to change order of some elements (for example some image, search box or navigation) to make the page more readable without much need of scrooling.

So I need to be able to access DOM and change order of some page elements (swap them).

Lets say I have an list and need to swap item 1 and 2.

<ul> <li>1</li> <li>2</li> </ul> 

I found a solution based on appending already items elements to <ul> by using function appendChild. However there is a problem with text nodes and it gets really complicated to do it for more difficult element structure, since the need of recreating it whole again.

Do you have any suggestion to improve it?

3
  • 1
    Time to invest in learning jQuery. It makes this type of activity a lot easier. Commented Oct 12, 2011 at 15:17
  • Can you be, please, more specific? I now that library, but some link to API useful for this would be helpful. Commented Oct 12, 2011 at 15:33
  • Have you tried using jquery sortable ? jqueryui.com/sortable Commented Jan 28, 2014 at 18:06

5 Answers 5

33

For this simple case (swapping the only two elements), you can just use appendChild():

(() => { const list = document.querySelector("ul"); list.appendChild(list.firstElementChild); })();
<ul> <li>List-item #1</li> <li>List-item #2</li> </ul>

The same node cannot exist in multiple positions; so, it's removed from its current position and placed at the end of the collection.

If you want to do more complicated sorting, you probably ought to create an array from the childNodes and get all crazy:

(() => { const frag = document.createDocumentFragment(); const list = document.querySelector("ul"); const items = list.querySelectorAll("li"); const sortedList = Array.from(items).sort(function(a, b) { const c = a.textContent, d = b.textContent; return c < d ? -1 : c > d ? 1 : 0; }); for (let item of sortedList) { frag.appendChild(item); } list.appendChild(frag); })();
<ul> <li>Dogs</li> <li>Snakes</li> <li>Cats</li> <li>Bugs</li> </ul>

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

Comments

6

In 2018 (and already a few years ago) this is possible with just CSS. Your use case would be solved by something like this:

ul { display: flex; flex-direction: column; } li:nth-child(2) { order: -1; } 

1 Comment

Too bad flex doesn't work / is buggy on fieldsets :(
4

You can use flex to change the order of the HTML elements very easily.

flex order: 0 by changing the order value you can decide where in the column the element appears

const ascButton= document.getElementById('asc') const decButton= document.getElementById('dec') //callback function for soring in ascending order const ascending = (a,b)=> a.innerHTML - b.innerHTML //callback function for soring in descending order const descending = (a,b)=> b.innerHTML - a.innerHTML let currentOrder = ascending ascButton.addEventListener('click', ()=>{	currentOrder = ascending order() }) decButton.addEventListener('click', ()=>{	currentOrder = descending order() }) const order = function(){	const ordered = [...document.getElementsByClassName('col')].sort(currentOrder) ordered.forEach((elem, index)=>{	elem.style.order = index }) } order()
.row{ display: flex; flex-direction: column; } .col{ padding: 20px; border: 1px solid gray; margin: 5px; order:3; }
<div class="row"> <div class="col " id="one">1</div> <div class="col " id="two">2</div> <div class="col " id="three">3</div> <div class="col " id="ten">10</div> <div class="col " id="four">4</div> <div class="col " id="five">5</div> </div> <button id="asc">ASC</button> <button id="dec">DESC</button>

You can find a much more complex implementation here https://jsfiddle.net/nijeesh4all/on5rsax8/

2 Comments

I like the usage of data-* attributes in your more complex example. It makes clearer what is filtered on 👌
I love the idea to use flex order for that, thank you!
2

wouldn't swapping innerHTML also work?

var myList = document.getElementsByTagName("ul")[0]; temp = myList.getElementsByTagName("li")[0].innerHTML; myList.getElementsByTagName("li")[0].innerHTML = myList.getElementsByTagName("li")[1].innerHTML; myList.getElementsByTagName("li")[1].innerHTML = temp; 

2 Comments

Be careful when writing to innerHTML it might have unwanted effects on event handlers and other such properties. Eg: stackoverflow.com/a/5113120/370786
it happens when you try this with document.body but not in this case. a simple example -> jsfiddle.net/tzv5db93
1

The following code will work for any number of siblings, to move one sibling up or down. Here, "element" is the element you want to move compared to its siblings.

move up:

function moveUp(element){ var upperSibling = element.previousElementSibling; if(upperSibling === null) return; upperSibling.insertAdjacentElement("beforebegin", element); } 

This inserts the element before ("beforebegin") its previous sibling (previousElementSibling).

move down:

function moveDown(element){ var lowerSibling = element.nextElementSibling; if(lowerSibling === null) return; lowerSibling.insertAdjacentElement("afterend", element); } 

This inserts the element after ("afterend") its next sibling (nextElementSibling).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.