Using insertAdjacentHTML with <a href...> - javascript

I am trying to modify a webpage with a chrome plugin I wrote myself. I'd like to add an additional link before a existing link.
I am using insertAdjacentHTML to add my new link before the original link.
But as soon as I use the a href it fails.
UPDATE
There were syntax errors in my code as many pointed out. I fixed these
This is the new code (but still won't work...webpage I want to alter seems to load forever and nothing happens):
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
anchors[i].href = "javascript:void(0)";
anchors[i].insertAdjacentHTML("beforebegin", "<a href='www.google.de'> bold text</a>")
}
Somehow the whole code works, if I don't add "a href". So this works:
anchors[i].insertAdjacentHTML("beforebegin", "<b> bold text</b>")
If I try the tag ..it somehow fails - can you give me a hint why?
Update2
I was finally able to solve this: I accidentally create an infinite loop. #Andy's answer points out a solutions to this.

Aside from the typos the big problem with the code is that getElementsByName returns a live list of anchor nodes. This can be useful in the right circumstances, but with your loop you're adding a new anchor to the list with each iteration so the loop is never able to finish and the browser hangs. To prevent this use querySelectorAll. It returns a static list instead.
var anchors = document.querySelectorAll('a');
for (var i = 0; i < anchors.length; i++) {
const newAnchor = 'bold text';
anchors[i] = 'javascript:void(0)';
anchors[i].insertAdjacentHTML('beforebegin', newAnchor);
}
Google
Bert
Ernie
In the long-run if you're going to be coding with JS and HTML a lot you'll probably find it easier to always use single quotes for JS strings etc, and double quotes for HTML attributes. That way the number of times you'll have to escape quotes will be limited.
You'll also find using a decent code editor like VSCode will help you see the typos in your code before they get to the browser.

You have a typo where you're setting the href:
anchors[i].href = "javascript:void(0)
You've opened a string there and not closed it. Simply add a " on the end.
Using a text editor with some decent syntax highlighting can help avoid these sorts of issues (although JS syntax highlighting is often a bit weird for this specific problem).
You would also have seen an error if you viewed the console in your browser developer tools (for most browsers these are opened by pressing F12).

Check you code, missing " and ;.
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
anchors[i].href = "javascript:void(0)";
anchors[i].insertAdjacentHTML("beforebegin", "<a href='www.google.de'> bold text</a>")
}

Related

How to use JavaScript to get all element from a dynamic scroll list?

Like the title said, how do I get all elements from a scroll div? The elements in the scroll list are loaded and destroyed dynamically.
I tried to crawl all course names from this website:
https://public.enroll.wisc.edu/search?term=1204
The code below only works for one time:
let list = document.getElementsByClassName('md-virtual-repeat-scroller')[0]
let childs = document.getElementsByClassName("result__name")
console.log(childs[0].innerText)
However, if I do this, I will get the same result for 10 times:
let list = document.getElementsByClassName('md-virtual-repeat-scroller')[0]
for(let i = 0; i < 10; i++) {
let childs = document.getElementsByClassName("result__name")
for(let j = 0; j < childs.length; j++) {
console.log(childs[j].innerText)
}
// scroll by 1000px every time
list.scrollBy(0, 1000)
}
I don't know what's the problem. Is it because that scrollBy() works asynchronously? But I tried to use async and await. It still doesn't work.
Give more information in less words as a possible. Many problems could be related to browser and its version, for example. How is this script called? Are you giving commands via browser console? Have you done a copy of the site and performed some modification on it? It's hard to understand the problem in a realistic level.
Tip: Avoiding use innerText. It's slower and is supported in many browsers only for compability to scripts written to old versions of IE. (I don't know why so many examples in internet use it as first option). User textContent instead.
It's always good to test the returned value of a function/methods - specially during the development of the program.
Never ask to the StackOverFlow community (and to any other) to write progams for you!
You question "how do I get all elements from a scroll div?" is so "loose". scroll div? The answer to this, independently to the "type of div" (and tag!) would be found below.
Your code seems to be no sense in order to do what you want. Why iterate from 0 to 10?
Look at this snipet. I think it will help you
const list = document.getElementsByClassName('md-virtual-repeat-scroller')[0];// if there is no intention to reassign it. Use [0] if you are sure it's the first element of this collection
let childs = list.getElementsByClassName("result__name"); // get only elements inside the first variable!
Use the iterator of the variable.
for(item of childs)
{
/*code*/
}
I am sure you will achieve your goals!
And never suggest us (Community) to code for you or even to resolve your problem. This sound very agressive! To you too! I'm sure.
I solved my problem by reading this article:https://intoli.com/blog/scrape-infinite-scroll/
The reason why I kept getting the same elements is that scrollBy() works asynchronously, so I have to wait then evaluate the page again. I am using puppeteer by the way.
please read the article, super helpful.

Opening multiple URLs with window.open

I'm pretty new to javascript, so apologies for the beginner question. Basically, I am having some problems with the window.open() method.
My code essentially takes a user string, adds a couple different variations to it, and those searches those different variations, and then is supposed to open a new window with each result. However, it seems that after my first window.open statement, the code stops executing. This is what I am working with:
var searchStrings = new Array(url1, url2, url3);
var arrayLength = searchStrings.length;
for (var i = 0; i<arrayLength; i++) {
window.open(searchStrings[i]);
}
I have tested the loop with code other than window.open to make sure it iterates through the array correctly, and I have set i to values higher than 0 to test opening the second or third item in the array.
It seems like window.open is only meant to be used once, or am I doing something else incorrectly?
Check this out: https://javascript.info/popup-windows
This documents correct usage of window.open() functionality.
Modern browsers block that kind of execution, due the risk of mis-using the functionality.
Imagine, you enter the page and 10x windows open, for no reason.
Actually, have a look you code works but chrome blocks the window and on the address bar you are notified. However Firefox blocks it completely, until manually disable the option.
windows.open can takes second parameter(name), if you want open multiple URLs you have to set unique name for each one. in your scenario you cant use this:
for (var i = 0; i < arrayLength; i++) {
window.open(searchStrings[i], '_wnd' + i);
}

What would be the drawbacks for creating "a" tags while ommitting the href attribute?

What I have in mind is an implementation for automatically populating the href attribute based on what's inside the a tag. I can only express this via javascript.
Example:
var links = document.getElementsByTagName("a");
for (var i = 0; i < links.length; i++) {
var elm = links[i];
var content = elm.innerHTML
if (content.indexof("http") !=-1 || content.indexof("www") !=-1) {
elm.href = content;
} else {
elm.href = "#";
}
}
Of course this is a very basic and not too well thought javascript implementation and would cause performance and SEO issues. What I was thinking about is more along the lines of suggesting it to W3C so they can plan on a native browser implementation that would save us time while coding.
We'd be able to:
Code an a tag without specifying a href
<a>http://google.co.uk/</a>
Result:
http://google.co.uk/
Make blank links for prototyping
<a>Click here</a>
Result:
Click here
Override this behaviour by specifying a href
Click here
Result: Unchanged.
Had these thoughts while doing the tedious job of copying and pasting the same URL hundreds of times into href attributes while creating extensive T&Cs pages. I'm sure I'm overlooking something.
The proposal would break existing code, so it is unlikely that it would have much chances of being considered very seriously. There are millions (well, billions, probably) of web pages that have a elements without href attribute, for various reasons (and such elements are valid). The proposal would make all of them functionally links, changing the meaning of documents.
There are other drawbacks too, but this one probably suffices.

How do I change getElementById 2nd time around?

I am creating a multiple choice question that requires the user to click an answer (radio button). If the user clicks the check answer button before selecting an answer, he is prompted to select an answer. This works fine. However, if the user then selects a wrong answer and clicks the check answer button, the appropriate response is displayed over the previous prompt. I tried changing the getElementById for the prompt to display "", but it didn't work. Any help would be appreciated.
for (i = 0; i < len; i++) {
if (document.Questions.Q_ans[i].checked == false) {
document.getElementById("reply_b").innerHTML = "Select answer before continuing.";
}
}
if (document.getElementById('answer_b').checked || document.getElementById('answer_c').checked) {
document.getElementById("reply_a").innerHTML = incorrect;
document.getElementById("reply_b").innerHTML = "";
}
This line fails since incorrect should either be defined as a variable or it should be wrapped in quotes:
document.getElementById("reply_a").innerHTML = "incorrect"; // <-- Should be in quotes
So your script never executes the line after.
Use Jquery, replace all the "document.getElementById('yourId')" for "$('#yourid')"
and you must have initialized a var len for your loop.
js:
for (var i = 0; i < len; i++) {
if (document.Questions.Q_ans[i].checked == false) {
$("#reply_b").innerHTML = "Select answer before continuing.";
}
}
if ($('#answer_b').checked || $('#answer_c').checked) {
$("#reply_a").innerHTML = incorrect;
$("#reply_b").innerHTML = "";
}
As #brian buck said, your script doesn't get executed after the incorrect statement which should be a defined variable or wrapped in quotes (to be executed as a string). Your script silently fails and basically does nothing (at least, nothing you can see).
A few things here I would also recommend:
Make sure to use var i in your loop to avoid scope error
Your first loop check seems a bit odd to me: for every (assumed) possible answer not checked, you display the same error. It is not critical, but your script does something each time instead of once. You could have, let's say, a boolean that you toggle when you discover that an answer has been checked somewhere, and assign your error statement at the end depending on the value of this boolean. However, my "naked" JS is a bit rusty for that situation, and I am totally sure that there are better solutions to it!
As it appears you haven't been notified of the script failure, I don't think you use any debugger. If you are doing JS in a web browser, you could use the embedded consoles. Otherwise, there are plenty of tools taht could help you a lot. I remember losing my hair when starting to play with JS, because it got silent everytime it wasn't happy...

Trying to fire off a bunch of onclicks all containing a different number

There is a page I can access that contains a bunch of links like this:
<a href="#" onclick="navigate(___VIEW_RAID_2, {raid_inst_id:556816});return false;">
The number after the raid_inst_id: is always going to be different and there will be multiples on the same page all with different numbers. I'm trying to put together a javascript that will scrape the page for these links, put them in an array and then cycle through clicking them.
Ideally, an alert causing a pause between onclicks would be helpful. I've been unsuccessful so far even trying to gather the numbers and just echoing them out let alone manipulating them.
Any hints or help would be greatly appreciated!
Below is a function I tried putting together just to see if I could capture some of the onclick values for further processing but, this produces nothing...
function closeraids(){
x=document.getElementsByTagName('a');
for(i=0;i<x.length;i++)
{
attnode=x.item(i).getAttributeNode('onclick');
alert("OnClick events are: " + attnode);
}
}
Wow - 4 months later and the same problem still exists. I decided to look into this again only to find my own posted question in my Google search! Does anyone have any thoughts on what could be done here? The function I'm trying to provide will be part of a Chrome extension I already provide to users. It uses a combination of a .js file I host on my webserver and injected html content.
Any help would be appreciated!
Had some fun while making this jsfiddle: http://jsfiddle.net/Ralt/ttkGG/
Mostly because I went onto using almost fully functional style... but well. Onto your question.
I'm using getAttribute('onclick') to get the string in there. It shows something like:
"navigate(___VIEW_RAID_2, {raid_inst_id:553516});return false;"
So I just built the necessary regex to match it, and capture the number after raid_inst_id:
var re = /navigate\(___VIEW_RAID_2, {raid_inst_id:(\d+)}\);return false;/;
It's mostly rewriting the string by escaping the parentheses and putting (\d+) where you want to capture the number. (\d+ is matching a number, () is capturing the matched string.)
Using match(), I can simply get the captured string as the last element. So, rewriting the code in old IE way:
var links = document.getElementsByTagName('a'),
re = /navigate\(___VIEW_RAID_2, {raid_inst_id:(\d+)}\);return false;/;
for (var i = 0, l = links.length; i < l; i++) {
var attribute = links[i].getAttribute('onclick'),
nb;
if (nb = attribute.match(re)) {
alert(nb.pop());
}
}

Categories