I have a list of href / text that I need to make anchors for and then display those anchors. Everything is fine until I actually click any of the anchors. They each only open a tab for the last href. I.e. if the href of the last element in the list is href_n, then every anchor links to href_n, even if the 'href' attribute is different.
//Current basic setup:
loop through list:
anchor = doc.create('a')
divElem = doc.create('div')
anchor.setAttribute('class', 'foo')
anchor.setAttribute('href', 'bar')
anchor.innerHTML = 'mytext'
anchor.addEventListener('click', function() {chrome.tabs.create({url: 'myurl'})});
divElem.appendChild(anchor)
container.appendChild(anchor)
Previously I tried using .onClick, but I kept having a problem with the event listener trying to just attach to the url. I am very amenable to a cleaner solution though that involves something simpler than an eventlistener.
Thanks much.
You mostly just need to change your click handler to not use variables that are not still valid. Here's sample code:
var urlList = [
"aaaa",
"bbbb",
];
var textList = [
"text1",
"text2"
];
function createAnchors(urls, text, container) {
for (var i = 0; i < urls.length; i++) {
var a = document.createElement("a");
var div = document.createElement("div");
a.href = urls[i];
a.innerHTML = text[i];
a.className = "foo";
a.addEventListener("click", function() {
chrome.tabs.create({url: this.href});
return(false);
});
div.appendChild(a);
container.appendChild(div);
}
}
The issue is that any variables in your event listener function are not evaluated until the click. So, in this case, you can avoid using them by just getting the url directly from the clicked link.
I hope you also realize that older versions of IE don't support addEventListener. This mozilla page shows you how you can handle that in the Internet Explorer section.
You need to create a closure:
var urls = [];
for(var i=0;i<urls.length;i++){
anchor.addEventListener('click',
(function(url) {
return function() {
chrome.tabs.create({url: url})
}
})(urls[i])
);
}
Related
I am making a JS function, which will change the icon of the document. Now, I know that this sounds simple, but it is not. I am trying to make a Library, so I need a function that can change the default icon to the desired icon and vice versa. It works fine if I try to change the default icon to the desired icon, but if I try to change the icon to the default one(the one with a gray globe), it does not work.
icon = function(dir){
if(typeof(dir)==="string"){
var elem = doc.createElement('link');
elem.rel = "icon";
elem.href = dir;
doc.head.append(elem);
}else if(typeof(dir)==="boolean"&&dir===false){
var toBeDel = [];
var currElems = document.querySelectorAll('link');
var i = 0; var f = 0;
while(currElems.length>=0){
if(currElems[i].rel=="icon"){
toBeDel.push(currElems[i]);
currElems.length--;
i++;
}
}
while(toBeDel.length>=0){
doc.head.removeChild(toBeDel[f]);
toBeDel.length--;
f++;
}
var elem = doc.createElement('link');
elem.rel = "icon";
elem.href = "/default/noimage.png";
doc.head.append(elem);
window.setTimeout(function(){
console.clear();
var len = efun.logs.length;
var sen;
var i = 0;
while(len>=0){
sen = efun.logs[i];
efun.gh = sen[0];
console.defaultLog(sen[0]);
len--;
i++;
}
},10);
}
else{
efun.cons("Error in icon() function, the parameter you have entered is not a string directory.");
}
}
Note: efun object is the main library object, efun.cons() is a shortcut to console.log(), efun.logs is an array which contains all console.logs() done. Note that I called the console.clear() function to remove the error which comes when I try to set the default icon since it does not exist. console.deafultLog() is a function, which console.logs() with it not being pushed into the efun.logs array. But the error is that I want to remove all the <link rel="icon" href="<!---directory here-->" elements from the head tag. There can be many elements with icons, so I want to remove all of them. For this, I used document.querySelectorAll() in an array, and did several while loops. But still, even though a new link element gets appended into the <head> tag, the previous ones which I want to remove remains there, so how can I remove all tags with <link> tag and rel="icon" attribute. Is there any fix to this?
I think you may have overcomplicated this.
You can delete all existing <link> tags with just one line
document.querySelectorAll('link[rel="icon"]').forEach(link => link.remove());
To revert back to the "globe" icon, you just need to change the url to something that doesnt exist.
var link = document.createElement('link');
link.rel = 'icon';
link.href = 'https://fake.url.com/';
document.getElementsByTagName('head')[0].appendChild(link);
If you want to handle errors better, you can use try catch blocks.
In order to learn Javascript, I created a little website on local.
I have a menu composed of "li", a empty "div", and several "section".
When a click is done on a "li", the appropriate "section" goes into the empty "div" and its class="hidden" is removed.
To make this, I have a loop on my "li" and when there is a click on one of them, a function swapContent() is called inside the li.addEventListener...
Everything works fine ! But, in one specific "section", I have buttons that also work with a click and addEventListener. And that doesn't work.
When I comment the code inside my script file and test it with the console, it works but not when it's called from the script.
I also tried including the javascript code related to those buttons inside the "li" loop right after where the addEventListener (click) with the swapContent() are called and it works !
window.addEventListener("load", function() {
const frame = document.getElementById('frame');
function swapSection(liText, secId){
let section = document.getElementById(secId);
let clone = section.cloneNode(true);
clone.classList.remove('hidden');
while (frame.firstChild) frame.firstChild.remove();
frame.appendChild(clone);
let h2Select = document.getElementsByClassName('hero');
h2Select[0].innerText = liText;
};
// -- Navigation --
var liList = document.querySelectorAll('[id^="li_"]');
for (var item of liList) {
let li = item;
let liId = li.id;
let liText = li.innerText;
// if <li> has an ID show section onclick
if (liId) {
const reg = /li/i;
let secId = liId.replace(reg, 'sct');
// Display content into frame on item menu's click
li.addEventListener('click', function(){
swapSection(liText, secId);
}, false);
}
};
// Buttons that don't work
const toChange = document.getElementById('toChange');
const btnDisable = document.getElementById('disable');
const btnEnable = document.getElementById('enable');
btnEnable.addEventListener("click", function(e) {
toChange.setAttribute("disabled", false);
toChange.innerText = 'Not Clickable'
}
);
btnDisable.addEventListener("click", function(e) {
toChange.removeAttribute("disabled");
toChange.innerText = "Clickable";
});
});
The code on https://codepen.io/Franz333/pen/vqGLZE
Thank you in advance
I'm trying to put a delete button on each li using JavaScript and to make an event handler that runs when a button is clicked that removes the li. However when I try to add the handler, I get:
Cannot read property 'addEventListener' of null
I think this is because I am referencing a class that not exist before run the function createbtn. So How can I solve this?
The Code:
I set the variables, put querySelector to buttons because I testing how to do it:
var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var list = document.querySelectorAll ("li");
var buttons = document.querySelector (".btn-danger");
var li = document.createElement("li")
How I create the button:
function createbtn() {
for (var i = 0; i < list.length; i++) {
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
list[i].appendChild(btn);
}
}
The function I try to run:
function liDel(){
li.parentNode.removeChild(li);
}
buttons.addEventListener("click", liDel);
This is my fiddle to see all the code.
The reason why you are getting the null error is because;
You have assigned the variable buttons to a node which doesn't exist yet. (Note that the button is created after the page has been loaded, which means .btn-danger hasn't yet been created at that time).
According to MDN the querySelector method does the the ff:
The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
Based on the code you have in the fiddle, here is a guide to achieve the desired results.
First of all, get rid of the global li variable on line 6.
The reason is that if you create a new li from the input, it will render on the same line because it's still referencing the same element node (I'm sure you've realized that)
then in your createListElement function, do the ff
function createListElement() {
var li = document.createElement('li');
li.appendChild(document.createTextNode(input.value));
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
btn.addEventListener('click', function(e){
if(!e) e = window.event;
try{
ul.removeChild(this.parentNode)
}catch(err){
alert(err.message)
}
})
li.appendChild(btn)
ul.appendChild(li);
input.value = "";
}
Then when you create the buttons, you have to attach the event listener function to it. So you do the ff in your createbtn function:
// To create a button
function createbtn() {
for (var i = 0; i < list.length; i++) {
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
btn.addEventListener('click', function(e){
if(!e) e = window.event;
try{
ul.removeChild(this.parentNode)
}catch(err){
alert(err.message)
}
})
list[i].appendChild(btn);
}
}
anyways, there are more efficient ways to do this. But this is a quick workable model based on the code in your fiddle
Rather than querying and adding the event to the buttons object
try the chaining inside the document load.
window.onload = function () {
document.querySelector('.btn-danger').addEventListener('click', liDel);
};
The above code should work!
Thanks a lot everybody, I got a solution after reading all your answers:
First I got rid the following:
var buttons = document.querySelector (".btn-danger");
var li = document.createElement("li")
Then create this function for remove the "li"
Using "this" you avoid the error for don't have a reference, because with that you don't care in what kind of element this is, you only now something is there and grab it for anything you need.
function liDel(){
ul.removeChild(this.parentNode);
}
and put this in createBtn for delete the existing "li" in the html:
btn.addEventListener('click', liDel);
then put this on createElement for do the same of the above, but for the new "li" creates with the DOM:
btn.addEventListener('click', liDel);
li.appendChild(btn);
And with that the problems was solved.
Thanks again and you can see how the page works on the fiddle
I hope it's not a problem to post much specific code here, but I figure it will be better explained if everyone can just see it, so I will give you my code and then I will explain my problem.
My code:
function addBeGoneLinks () {
var beGoneClassElems;
var beGoneSpan;
var beGoneLink;
var beGonePrintSafe;
var spacesSpan;
//var middotSpan = document.createElement ('span');
var interactionContainer = document.getElementsByClassName('feedItemInteractionContainer');
for (var i=0; i<children.length; i++)
{
beGonePrintSafe = false;
beGoneClassElems = children[i].getElementsByClassName('beGone')
beGonePrintSafe = true;
if (beGoneClassElems.length == 0)
{
beGoneLink = document.createElement('a');
beGoneLink.href = 'javascript:void(0);';
beGoneLink.appendChild(document.createTextNode('Be Gone'));
beGoneLink.className = 'beGone';
beGoneLink.id = 'beGoneLink' + i.toString();
beGoneLink.addEventListener ("click", function() {beGone();}, false);//This line!
beGoneLink.align = 'right';
spacesSpan = document.createElement('span');
spacesSpan.innerHTML = ' - ';
if (interactionContainer[i] != undefined)
{
interactionContainer[i].appendChild(spacesSpan);
interactionContainer[i].appendChild(beGoneLink);
}
}
}
}
Here I have a function from a Greasemonkey script that I am working on. When one of the links is clicked, my aim is to have it call the function beGone() which will, among other things, remove the whole element a few parents up, thereby removing their sibling's, their parents and their parents' siblings, and one or two levels after that.
My idea was just to get the id of the link that was pressed and pass it to beGone() so that I could then get the parents using its id, but I do not know how to do that. Am I able to have the id of a link passed by the function that it calls? If not, is there any other way to do this?
I am not sure whether I am missing some really simple solution, but I haven't been able to find one rooting around the web, especially because I was unsure how I would search for this specific problem.
Try this:
beGoneLink.addEventListener("click", beGone, false);
beGone = function (evt) {
evt.target; // evt.target refers to the clicked element.
...
}
You can then use evt.target.id, evt.target.parentNode, etc.
Might be a very simple javascript injection question, but say I have an image html tag:
<img src="rainbow.gif">
I wanted to perform a javascript, such that when clicked on the image, it doesn't go to the myfile.htm. In other words, I wanted to strip the a href which surrounds the img. How can I do this in javascript? Say that I have the following to reference the image tag:
document.elementFromPoint(%f, %f)
f can be replaced by any double/float value
If you have a reference to the img element, then its parent (parentNode) will be the link (in the structure you've given). Three options:
Remove the link entirely
Disable the link
Change the link's href
1. Remove the link entirely
You can remove the link entirely by doing this:
var link = img.parentNode,
linkParent = link.parentNode;
linkParent.insertBefore(img, link);
linkParent.removeChild(link);
That uses parentNode to find the parent and grandparent, insertBefore to move the image, and removeChild to remove the link. Note that this assumes the image is the only thing in the link.
2. Disable the link
If you want to keep the link but render it useless, you can do this:
var link = img.parentNode;
if (link.addEventListener) {
link.addEventListener("click", function(event) {
event.preventDefault();
}, false);
}
else if (link.attachEvent) {
link.attachEvent("onclick", function() {
return false;
});
}
else {
link.onclick = function() {
return false;
}
}
3. Change the href of the link:
This is trivial, just set the href property of the link element (which you can get because it's the parent node of the image) to whatever you want:
img.parentNode.href = /* ...something else */;
For instance:
img.parentNode.href = "http://stackoverflow.com";
...would change the link to point to Stack Overflow.
Live example
Some references:
DOM2 Core
DOM2 HTML
DOM3 Core
HTML5 Web Application APIs
<a id="anchorWithImage" href="myfile.htm"><img src="rainbow.gif"></a>
Why not grab the anchor, then set its href to nothing:
var a = document.getElementById("anchorWithImage");
a.href = "javascript:void(0)";
Or grab it and set its click event to cancel the default action, which is to browse to the location of its href property
a.onclick = function(e) {
e.preventDefault();
}
Or do you want to grab all anchors that have an image as their child element, and strip out their href?
jQuery would make this easy, if that's an option for you
$("a").filter(function() {
return $(this).children("a").length === 1;
}).attr("href", "javascript:void(0)");
or
$("a").filter(function() {
return $(this).children("a").length === 1;
}).click(function() { return false; }); //returning false from jQuery handlers
//prevents the default action
EDIT
If you were to have a reference to the image, and wanted to set its parent's anchor's href, you'd grab it with the parentNode property:
var img = document.getElementById("imgId");
var a = img.parentNode;
a.href = "javascript:void(0)";
With jQuery you could use something similar to this
$("a").has("img").click(function(e).preventDefaults();});
Basically all this line does is identifies all tags within the document containing an tag disables standard event process
From your comment on another answer, it sounds like you actually want to change/eliminate the target of links at a specific position in the page. You could do something like this:
var el = document.elementFromPoint(10, 10);
while(el) {
if(el.nodeName.toLowerCase() == 'a')
el.href = 'javascript:';
el = el.parentElement;
}
This would loop up from the selected element, identify if the element is an anchor, and set the href to something that does nothing.
you can change the href of a tag on window load itself, so you need not worry when it is clicked.
window.onload = fundtion(){
var imgs = document.getElementsByTagName('img');
for(var i=0;i<imgs.length;i++){
var parentElem = imgs[i].parentNode;
if(parentElem.tagName === 'A')
parentElem.setAttribute("href", "javascript:void(0)");
}
};