How to get first childnode within a for loop - javascript

I'm trying to create a script that gets all the sections of documentation and creates a navigation with the id for a link and the H2 as the link text. I've tried several ways and the title is undefined. I've tried using a class, getting the first child node, and converting the nodelist to an array.
http://codepen.io/brooksroche/pen/XmpNaq?editors=101
if (document.getElementsByClassName("doc-section")) {
var sections = document.getElementsByClassName("doc-section"),
sidebar = document.getElementById('sidebarNav'),
navLinks = "";
for (var i = 0; i < sections.length; ++i) {
var current = sections[i],
anchorID = current.id,
title = current.childNodes[0].text,
navLink = '<li>' + title + '</li>',
navLinks = navLinks + navLink;
}
if (sidebar) {
sidebar.innerHTML = navLinks;
}
}

Use this instead (when collecting headers):
title = current.children[0].textContent
Demo. In other words, you should place children instead of childNodes, as with the latter both elements and text nodes are collected. Quoting the docs:
childNodes also includes e.g. text nodes and comments. To skip them,
use ParentNode.children instead.
In this particular case, whitespace between closing tag and opening tag was actually the first childNode of section element. You were able to get its text with .data property, but it was obviously of no use.
Actually, you might consider this as a safer alternative:
title = current.querySelector('.sectionTitle').textContent
... so that when the corresponding element's order is changed, you'll still be able to collect the text from it (if class is the same, of course).

Related

Getting all classes from one element and adding them to another element in vanilla JavaScript

I'm trying to get all classes from one element, then add them to another element created dynamically. I was originally stuck on how to do this, but as I was typing out this question, I worked out a solution. However, it seems a bit verbose. Is there a way to do this same thing more efficiently, i.e. with fewer lines of code?
let classes = this.nextElementSibling.classList; // get classes from target element
classes += ''; // convert classlist object to string
let class_array = classes.split(' '); // convert string to array
const my_div = document.createElement('div'); // create a new div
for(i=0; i<class_array.length; i++) { // loop through array and add classes to the div
my_div.classList.add(class_array[i]);
}
Thanks in advance.
The className will give you a space-separated string of class names an element has. Just use that.
const my_div = document.createElement('div');
my_div.className = this.nextElementSibling.className;

Changing Text using JS .getElementsByClassName: Class Names are the Same, and I only want to change the text of one

I'm not exactly sure how to word this, but I am using Javascript to change text. I am using Javascript on the site Quizlet. As you can see, there are two columns: terms and definitions. As of now, the script changes both when I only want it to change the term list. Here's a video, too: https://drive.google.com/file/d/1ly3askpLQjzXeCMx9Mk9iVpSEXCw6i25/view
Works, but changes both:
var myClasses = document.getElementsByClassName("ProseMirror");
for (var i = 0; i < myClasses.length; i++) {
myClasses[i].innerHTML = "new content";
}
I tried this, but it didn't work:
var myClasses = document.getElementsByClassName("WordList");.document.getElementsByClassName("ProseMirror");
for (var i = 0; i < myClasses.length; i++) {
myClasses[i].innerHTML = "new content";
}
If you're trying to find a .ProseMirror element only when it's inside a .WordList element, you can use a CSS selector for that with querySelector:
const element = doucment.querySelector(".WordList .ProseMirror");
element.innerHTML = "new content";
That finds the first element with the class ProseMirror that's also inside an element with class WordList.
I don't think you want a list of matches, but if you did, you'd use querySelectorAll (which returns a NodeList of all matches) instead of querySelector (which returns the first matching element).
You can use document.querySelectorAll to get the elements with multiple classes.
document.querySelectorAll('.WordList.ProseMirror');

Javascript: Add same <li> to mulitple <ul> [duplicate]

I just notice I couldn't do
var d1 = document.createElement('div');
var d2 = document.createElement('div');
var p = document.createElement('p');
d1.appendChild(p); // d1 has p now
d2.appendChild(p); // d2 has p now
// but where is p in d1 ?
Some would say it's logic, but well, when I first noticed that I thought how uncool it was.
Why isn't that possible ?
The DOM is a tree structure.
When you append an element, you change its parent.
A node, in the browser, is much more than just the text inside your P (that string could be shared, in fact). It also has a position, dimensions, a visibility, receives events that could have been fired in child elements, propagate events to its parent, and so on. Everything here depends on the position in the tree. Just like would many CSS selectors. It doesn't make a lot of sense to imagine it's the same element at two places, it's better to think about it as two nodes, with maybe some identical content.
If you want to have the same content at two places, you have to clone it.
jQuery's appendTo() method inserts "every element in the set of matched elements to the end of the target". Try this:
p.appendTo(".div-class1, .div-class2")
for AppendChild same element multiple times , we can use this way :
//main function
function appendChildMultiple(parent) {
//check function argument is an element
if (parent.nodeType !== undefined) {
const pTag = document.createElement("p");
pTag.innerText = "This is the appended element";
//finally append child to parent
parent.appendChild(pTag);
}
}
and :
// target the wrapper and create test elements
const wrapper = document.querySelector(".wrapper");
const d1 = document.createElement("div");
const d2 = document.createElement("div");
//append test elements to wrapper
wrapper.appendChild(d1);
wrapper.appendChild(d2);
//use appendChildMultiple function
appendChildMultiple(d1);
appendChildMultiple(d2);
//we appended "pTag" multiple times
if we use Functions , we can AppendChild same element multiple times whitout cloneNode
https://codepen.io/kiumad/pen/eYMNKYa

How to get multiple headers/footers in a document with Google Apps Script

Im trying to replace a text in a Google Document header which has "Different first page Header/Footer" active. I succesfully replace text in any other page header except on first page.
...
var something = "Some string.";
var copyId = DriveApp.getFileById(docTemplate).makeCopy(name).getId();
var copyDoc = DocumentApp.openById(copyId);
var copyHeader = copyDoc.getHeader();
copyHeader.replaceText('keySomething', something);
...
I looked at the documentation but didn't see how to do it. I even tried with "getHeaders()" (in plural) but that class doesn't exist.
How I can replace the text in the first page header/footer?
Thanks,
Iván
copyHeader.getParent().getChild(2); //I'm using your variable
This will point to the header on the first page. The "2" in getChild(2) may or may not vary but I have added a function, seeChildren(), on the third block of code in this answer.
If you are trying to replace all instances of a string in the document, use this with replaceText()
copyHeader.getParent(); /*this points to the whole document (unless the
header's parents is not the whole)*/
//getbody(), getfooter(), etc (i.e. siblings of header) should work
If you want to know the x of getChild(x) for the footer,
function seeChildren(){
var doc = DocumentApp.getActiveDocument();
var bod = doc.getBody();
var fol = bod.getParent();
for (i = 0; i<fol.getNumChildren(); i++){
var child = fol.getChild(i);
bod.appendParagraph(child + ": Index " + fol.getChildIndex(child));
}
}
This will append the names of the document's children (DocumentBodySection, HeaderSection, HeaderSection, FooterSection, FooterSection, etc) and their respective indices on the body section (0,1,2,...,number of children minus 1). Also, note that this uses getActiveDocument(), the file must be open for the function to work.
copyHeader.getParent().getChild(3).replaceText('current text','new text');
This will point to the header on the first different page.

Trouble Replacing Multiple Links With iFrame Via Javascript

I'm trying to parse a page with javascript to replace links belonging to a specific class with an iframe to open a corresponding wikipedia page [so that rather than having a link you have an embedded result]. The function detects links properly but something about the replaceChild() action causes it to skip the next instance... as if it does the first replace and then thinks the next link is the one it just worked on, probably as a result of the loop.
For example, if there's 2 links on the page, the first will parse and the second will not even be seen but if there's 3, the first two will be parsed using the attributes from the first and third.
Can anyone suggest an alternative way of looping through the links that doesn't rely on a count function? Perhaps adding them to an array?
Sample Links
wiki it
Sample Javascript
(function(){
var lnks = document.getElementsByTagName("a");
for (var i = 0; i < lnks.length; i++) {
lnk = lnks[i]; if(lnk.className == "myspeciallinks"){
newif=document.createElement("iframe");
newif.setAttribute("src",'http://www.wikipedia.com');
newif.style.width="500px";
newif.style.height="100px";
newif.style.border="none";
newif.setAttribute("allowtransparency","true");
lnk.parentNode.replaceChild(newif,lnk);
}
}
})();
The problem here is that document.getElementsByTagName returns a NodeList and not an array. A NodeList is still connected to the actual DOM, you cannot safely iterate over its entries and at the same time remove the entries from the DOM (as you do when you replace the links).
You will need to convert the NodeList into an array and use the array for iteration:
(function(){
var lnksNodeList = document.getElementsByTagName("a");
// create an array from the above NodeList and use for iteration:
var lnks = Array.prototype.slice.call(lnksNodeList);
for (var i = 0; i < lnks.length; i++) {
var lnk = lnks[i];
if (lnk.className == "myspeciallinks") {
var newif = document.createElement("iframe");
newif.setAttribute("src", 'http://www.wikipedia.com');
newif.style.width = "500px";
newif.style.height = "100px";
newif.style.border = "none";
newif.setAttribute("allowtransparency", "true");
lnk.parentNode.replaceChild(newif, lnk);
}
}
})();
According to the MDN documentation:
Returns a list of elements with the given tag name. The subtree underneath the specified element is searched, excluding the element itself. The returned list is live, meaning that it updates itself with the DOM tree automatically. Consequently, there is no need to call several times element.getElementsByTagName with the same element and arguments.
Therefore, the collection shrinks every time you replace an a. You could change your loop to decrement i whenever you do a replace.

Categories