0

Since .foreach and .map won't work on a nodelist, is the only way to work with the elements in a nodelist through a for loop?

What I'm trying to accomplish is adding different event listeners to the different elements within a nodelist. If the element has the class name of "bold", then the iBold() function should be run, and likewise for "italics" and "underline". Having multiple for loops running to handle each individually feels excessive, so that's why I'm trying to work with one loop to handle all rich text. However, if there's a better way to go about this, I'd really like to know since it seems as though I'm just over-thinking all of this.

var QSA = document.querySelectorAll('div > form > div > a.richText');
for (var rtIndex = 0; rtIndex < QSA.length;rtIndex++) { //Rich text event listeners
var rtid = QSA[rtIndex].id;
var targetiFrame = document.getElementById(rtid).getAttribute('data-pstid');
if (document.getElementById(rtid).className == "richText bold") { //Bold text event listener
    QSA[rtIndex].addEventListener('click', function() {  
        if (targetiFrame != 0) {iBold(targetiFrame);}
        else {
            document.getElementById('richTextField').contentDocument.execCommand('bold', false, null); 
            document.getElementById('richTextField').contentWindow.focus();
        }
    }, false);
} else if (document.getElementsByClassName('richText')[rtIndex].className == 'richText underline') { //Underline text event listener
    document.getElementsByClassName('richText')[rtIndex].addEventListener('click', function() {
        if (targetiFrame == 0) {
            document.getElementById('richTextField').contentDocument.execCommand('underline', false, null); 
            document.getElementById('richTextField').contentWindow.focus();
        } else {iUnderline(targetiFrame);}
    }, false);
} else if (document.getElementsByClassName('richText')[rtIndex].className == 'richText italic') { //Italic text event listener
    document.getElementsByClassName('richText')[rtIndex].addEventListener('click', function() {
        if (targetiFrame == 0) {
            document.getElementById('richTextField').contentDocument.execCommand('italic', false, null); 
            document.getElementById('richTextField').contentWindow.focus();
        } else {iItalic(targetiFrame);}
    }, false);
}   

}

    for (var sbmtIndex = 0;sbmtIndex <  document.getElementsByClassName('sbmtPost').length;sbmtIndex++) { //Event listener for submitting posts or comments
    var iSubmt = document.querySelectorAll('form > div')[sbmtIndex];
    document.querySelectorAll('form > div > .sbmtPost')[sbmtIndex].addEventListener('click', function() {
        var pstData = iSubmt.querySelector('form > div > .sbmtPost').getAttribute('data-cmtid');
        var cPrntID = iSubmt.querySelector('form > div > .sbmtPost').getAttribute('data-pstid');
        sendData(pstData, cPrntID); //Post Data (data being the id) and Comment Parent Id. Comments are posts. Variables only used for comments
    }, false); 
}
Azrael
  • 621
  • 2
  • 7
  • 16
  • 3
    Please, chache your selector queries in variables to make your code readable (and performant as a side-effect). – Bergi Jan 15 '14 at 00:08
  • 1
    ^^ What he said, you should at least avoid calling the same QSA all those times just the get the same data – adeneo Jan 15 '14 at 00:09
  • Thank you @Bergi for emphasizing readability over performance. That's refreshing. – Wayne Jan 15 '14 at 00:14

2 Answers2

0

If you don't mind converting your NodeList to an Array, you can use:

var nodeArray = Array.prototype.slice.call(nodeList);

Then you can use all the functional methods on the resulting Array.

Note: this is not cross-browser compatible, but neither is .forEach, so I don't think it's an issue.

Amadan
  • 191,408
  • 23
  • 240
  • 301
  • How is this not cross-browser compatible? – Bergi Jan 15 '14 at 01:12
  • 1
    Bergi: Because I believe `Array.prototype.slice` couldn't handle a non-`Array` `this` in IE8 and earlier. I could be mistaken. – Amadan Jan 15 '14 at 01:24
  • Ooops, [you're right](http://stackoverflow.com/a/3199627/1048572). However, let's overwrite it with a function that can when we'd care about IE. – Bergi Jan 15 '14 at 01:27
0
<div class="btn" data='btn1'>btn1</div>
<div class="btn" data='btn2'>btn2</div>
<div class="btn" data='btn3'>btn3</div>

const btns = document.getElementsByClassName('btn');

function getBtns(el, callback) {
  Array.prototype.forEach.call(el, function(node) {
    // Wrap below in if() condition here.
    node.addEventListener('click', callback);
  });
}

getBtns(btns, function() {
  console.log(this.getAttribute('data'));
});

this points to the button that's clicked.

michaelzick
  • 366
  • 1
  • 2
  • 9