Reputation: 35
I have a script that returns a list in alphabetical order as follows
<div id="x">
<ul>
<li>Apple
<li>Banana
<li>Blackberry
<li>Blueberry
<li>Cherry
<li>Cranberry
</ul>
</div>
However there are many items (almost 100) in the list and I am hoping to rearrange them as follows
<div id="x">
<span id="A">A</span>
<ul>
<li>Apple
</ul>
<span id="B">B</span>
<ul>
<li>Banana
<li>Blackberry
<li>Blueberry
</ul>
<span id="C">C</span>
<ul>
<li>Cherry
<li>Cranberry
</ul>
<div>
I'm not really sorting fruit btw, this is just an example.
It MUST be in that form, for reasons that matter not, I just need help creating and appending the span elements and the individual lists.
I have tried using inner/outer HTML and I'm finding it really really difficult. I currently have something like this:
function getAllLists()
{
var page = document.getElementById("x")
var allLists = page.getElementsByTagName("li");
var num = allLists.length;
//Some form of a for counter loop here
for (var counter = 0; counter < num; counter++) {
var first=allLists[counter].outerHTML;
var second=allLists[counter+1].outerHTML;
var firstletter= (allLists[counter].substring(0, 1)).toUpperCase();
var secondletter= (allLists[counter+1].substring(0, 1)).toUpperCase();
allLists[counter].outerHTML = '<span id="'+firstletter+'">'+firstletter+'</span>'+first;
}
}
PLEASE PLEASE PLEASE PLEASE AVOID USING JQUERY.
I can't stress this enough!!
Not only do I find it extremely difficult to understand, as I am still an amateur at javascript and find js already difficult enough as it is, the syntax for jquery is like just stupidly hard to understand.
I am certain it is possible to achieve what I am aiming for WITHOUT the need to use jquery.
Any ideas? all help/comments/ideas are more than appreciated.
Many thanks.
Upvotes: 1
Views: 2309
Reputation: 147453
Firstly forget all about manipulating the DOM using inner/outerHTML. They are handy for inserting chunks of HTML or sections of documents, but they are definitely not intended for general DOM manipulation.
Use DOM methods.
Firstly, load all the LI elements into an array. Then sort them using a sort function. Then put them back into the DOM wrapped in UL elements and separated by spans each time the first letter changes.
Here's a function that does the job. It sorts the lIs, not sure if that's really needed. If not, the function becomes a lot simpler.
<script type="text/javascript">
// Simple helper
function getText(el) {
if (typeof el.textContent == 'string') {
return el.textContent.replace(/^\s+|\s+$/g,'');
}
if (typeof el.innerText == 'string') {
return el.innerText.replace(/^\s+|\s+$/g,'');
}
}
function sortLIs(id) {
// Get the element
var el = document.getElementById(id);
// Get the UL element that will be replaced
var sourceUl = el.getElementsByTagName('ul')[0];
// Get the LIs and put them into an array for sorting
var nodes = sourceUl.getElementsByTagName('li');
var li, lis = [];
for (var i=0, iLen=nodes.length; i<iLen; i++) {
lis[i] = nodes[i];
}
// Sort them
lis.sort(function(a, b) {
return getText(a) > getText(b)? 1 : -1;
});
// Now put them into the document in different ULs separated
// by spans.
// Create some temporary elements for cloning
var ul, ulo = document.createElement('ul');
var sp, spo = document.createElement('span');
var frag = document.createDocumentFragment(); // fragments are handy
var firstChar, currentChar;
// For each LI in the array...
for (i=0; i<iLen; i++) {
li = lis[i];
firstChar = getText(li).substr(0,1) || '';
// If first char doesn't match current, create a new span
// and UL for LIs
if (firstChar !== currentChar) {
currentChar = firstChar;
// New span
sp = spo.cloneNode(false);
sp.appendChild(document.createTextNode(firstChar.toUpperCase()));
sp.id = firstChar;
frag.appendChild(sp);
// New UL
ul = ulo.cloneNode(false);
frag.appendChild(ul);
}
// Add the li to the current ul
ul.appendChild(li);
}
// Replace the UL in the document with the fragment
el.replaceChild(frag, sourceUl);
}
</script>
<div id="x">
<ul>
<li>Cherry
<li>Banana
<li>Apple
<li>Blueberry
<li>Cranberry
<li>Blackberry
</ul>
</div>
<button onclick="sortLIs('x');">Sort</button>
Note that the LIs are just moved to the document fragment and that the original UL is replaced by multiple elements. I've jumbled the LIs to show that the sort works.
If you have the array as text, then:
var fruits = ['Cherry','Banana','Apple','Blueberry',
'Cranberry','Blackberry'].sort();
function insertFruits(id) {
var el = document.getElementById(id);
// Check that the above worked
if (!el) return;
var frag = document.createDocumentFragment();
var li, lio = document.createElement('li');
var ul, ulo = document.createElement('ul');
var sp, spo = document.createElement('span');
var firstChar, currentChar;
for (var i=0, iLen=fruits.length; i<iLen; i++) {
fruit = fruits[i];
firstChar = fruit.substr(0,1).toUpperCase();
if (firstChar !== currentChar) {
currentChar = firstChar;
sp = spo.cloneNode(false);
sp.appendChild(document.createTextNode(firstChar));
sp.id = firstChar;
frag.appendChild(sp);
ul = ulo.cloneNode(false);
frag.appendChild(ul);
}
li = lio.cloneNode(false);
li.appendChild(document.createTextNode(fruit));
ul.appendChild(li);
}
el.appendChild(frag);
}
Upvotes: 2
Reputation: 883
Well, this is the way I get it done:
var allLists, elements, item, lastLetter, lastUl, letter, page, span, _i, _len;
page = document.getElementById("x");
allLists = page.getElementsByTagName("li");
lastLetter = null;
lastUl = null;
elements = document.createDocumentFragment();
for (_i = 0, _len = allLists.length; _i < _len; _i++) {
item = allLists[_i];
letter = item.innerText[0].toUpperCase();
if (letter !== lastLetter) {
lastLetter = letter;
span = document.createElement('span');
span.innerText = letter;
span.id = letter;
elements.appendChild(span);
lastUl = document.createElement('ul');
elements.appendChild(lastUl);
}
lastUl.appendChild(item.cloneNode(true));
}
while (page.firstChild) page.removeChild(page.firstChild);
page.appendChild(elements.cloneNode(true));
See this working here: http://jsfiddle.net/HjWhY/
Upvotes: 0
Reputation: 65815
<body>
<div id="x">
<ul>
<li>Apple
<li>Banana
<li>Blackberry
<li>Blueberry
<li>Cherry
<li>Cranberry
</ul>
<ul id="new"></ul>
var list = document.querySelector('#x ul'),
newUl = document.getElementById('new'),
fruits = [],
key = "A";
for(var i=0; i<list.children.length; i++){
fruits.push(list.children[i].innerText);
}
fruits.sort();
for(var i=0; i<fruits.length; i++){
if(key == fruits[i].split('')[0]){
var span = document.createElement('span'),
li = document.createElement('li');
span.setAttribute('id', key);
li.innerText = fruits[i];
if(document.getElementById(key)){
document.getElementById(key).appendChild(li);
}
else{
span.appendChild(li);
newUl.appendChild(span);
}
}
if(fruits[i+1]){
key = fruits[i+1].split('')[0];
}
}
Upvotes: 0