Reputation: 7295
I'm making creating some Javascript code so that the overflowing menu links would move into a separate menu called more.
The first time it is loaded, it works perfectly. However, when it is run again, things start shuffling...
Snippet here:
var tele = document.getElementById('teleporter'),
rec = document.getElementById('receiver');
window.onresize = resize;
resize();
function resize() {
var rChildren = rec.children,
numW = 0;
for (var i = 0; i < rChildren.length; i++) {
var child = rChildren[i];
var fragment = document.createDocumentFragment().appendChild(child);
child.outHTML = '';
tele.appendChild(fragment);
}
var teleW = tele.offsetWidth,
tChildren = tele.children;
for (var i = 0; i < tChildren.length; i++) {
var child = tChildren[i];
numW += child.offsetWidth;
if (numW > teleW) {
var fragment = document.createDocumentFragment().appendChild(child);
child.outHTML = '';
rec.appendChild(fragment);
i--;
}
}
}
#teleporter {
height: 20px;
overflow: hidden;
box-sizing: border-box;
padding: 0;
}
li {
float: left;
padding: 0 10px;
box-sizing: border-box;
list-style: none;
}
<ul id="teleporter">
<li>List item 0</li>
<li>List item 1</li>
<li>List item 2</li>
<li>List item 3</li>
<li>List item 4</li>
<li>List item 5</li>
<li>List item 6</li>
<li>List item 7</li>
<li>List item 8</li>
<li>List item 9</li>
<li>List item 10</li>
<li>List item 11</li>
<li>List item 12</li>
<li>List item 13</li>
</ul>
<div>More:
<ul id="receiver"></ul>
</div>
Why isn't it working?
Upvotes: 3
Views: 227
Reputation: 44000
To ensure that the <li>
are always in order, we make each <ul>
a flex container and then assign each <li>
the CSS property order
Details are commented in example
// Collect all <li> into an array
const items = Array.from(document.querySelectorAll('li'));
// Assign each <li> the CSS property {order: index}
items.forEach((item, index) => item.style.order = index);
// Bind the window to the resize event
window.onresize = resize;
// Call resize() for an initial sizing
resize();
function resize(e) {
// Reference both <ul>
const tX = document.querySelector('.tX');
const rX = document.querySelector('.rX');
// Get the width of tX
let tXW = tX.offsetWidth;
// Getv the width of the first <li>
let itemW = document.querySelector('li').offsetWidth;
/*
Divide the current width of tX by the width of a <li>
the result is the number of <li> that can fit in tX
in a single line
*/
let tXTotal = Math.floor(tXW / itemW) - 1;
/*
First array are the first <li> up to the last <li> that
can fit inside of tX
Second array is the remaining <li>
*/
let tXArray = items.slice(0, tXTotal);
let rXArray = items.slice(tXTotal);
// Append the array of <li> to the appropriate <ul>
tXArray.forEach(item => tX.append(item));
rXArray.forEach(item => rX.append(item));
}
all {
box-sizing: border-box;
margin: 0;
padding: 0;
}
main {
padding: 5vh 15vw 5vw 10vh;
}
ul {
list-style: none;
margin-left: -40px;
}
.tX {
display: flex;
flex-flow: row nowrap;
align-items: center;
max-width: 75vw;
height: 20px;
padding-right: 25vw;
}
.rX {
display: flex;
flex-flow: row wrap;
align-content: center;
}
li {
min-width: max-content;
margin: 0 8px 8px;
}
<main>
<ul class="tX">
<li>List item 00</li>
<li>List item 01</li>
<li>List item 02</li>
<li>List item 03</li>
<li>List item 04</li>
<li>List item 05</li>
<li>List item 06</li>
<li>List item 07</li>
<li>List item 08</li>
<li>List item 09</li>
<li>List item 10</li>
<li>List item 11</li>
<li>List item 12</li>
<li>List item 13</li>
</ul>
<div>More:
<ul class='rX'></ul>
</div>
</main>
Upvotes: 0
Reputation: 2449
I rewrote your resize function to avoid for loops, most probably error is in the hoisting of your i's, and unless you are doing it for a specific reason you can avoid the fragment variable, find below the modified resize, works
function resize() {
const rChildren = rec.children;
let numW = 0;
[...rChildren].forEach(item => {
item.outHTML = '';
tele.appendChild(item);
})
const teleW = tele.offsetWidth,
tChildren = tele.children;
[...tChildren].forEach(item => {
numW += item.offsetWidth;
if (numW > teleW) {
item.outHTML = '';
rec.appendChild(item);
}
});
}
updated fiddle: https://jsfiddle.net/e34p0t6w/3/
Upvotes: 1