Canot get the href value - javascript

Hi I need to valid the href is empty or not on my page using javascript. I searched the site and found some example, but it didn't worked for me. I must miss something that I didn't notice. Would someone point me the good direction and my mistake. I got the error" Unable to get property 'getattribute' of undefined or null reference. The <a> element is like that <a name="playback" href=""> on html file.
Thanks in advance.
There is my code which is run on load event:
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++)
{
anchors[i].onclick = function() {
if (anchors == null) {
alert('null');
}
else {
var link = anchors[i].getAttribute("href");
//var link= anchors[i].attributes['href'] this line doesn't work too.
}
}
}
}

In your code, the call to getAttribute is inside a closure (that is, a function defined "inline" without a name) that is assigned to the onlick event handler of the link. Therefore that code isn't execxuted right away - it doesn't run before the onclick handler triggers.
When the onclick header triggers, two things are passed to the callback function: the element on which the event was triggered is assigned to the this variable of the functions context - and the event itself is passed as first parameter. anchors however is undefined in the scope of that callback.
So, use either of those:
anchors[i].onclick = function () {
var link = this.getAtrribute("href");
}
 
anchors[i].onclick = function (event) {
var link = event.target.getAttribute("href");
}

You have got a scope problem.
The following code will output 3:
for (var i = 0; i < 3; i++) {
}
console.log(i); // 3
Similar to the example above your onclick is fired after the loop is done.
So i in your example would equal to anchors.length.
And anchors[anchors.length] === undefined.
To solve this problem you have to create a new scope.
For example you could use an Immediately-Invoked Function Expression (IIFE):
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++)
{
(function(j){
anchors[j].onclick = function() {
if (anchors == null) {
alert('null');
}
else {
var link = anchors[j].getAttribute("href");
}
}
}
}(i));
}

You need to use closure if you want to do it this way since you are using the shared i variable which would have been having last value of iteration when your handler runs on click. But since you are looking at that particular anchor, try binding it with bind an event listener and access it using this.href:
You can use addEventListener and for older browser support attachEvent
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener('click', function () {
var link = this.getAttribute("href");
})
};
Demo
Or :
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
anchors[i].onclick = getHandler(i);
}
function getHandler(i) {
return function () { //Now each of your handler has its own `i`
var link = anchors[i].getAttribute("href");
}
}
Demo

I have never seen getAttribute before so I performed some tests on it. It turns out that href and getAttribute("href") are quite different. Namely href is the absolute url and getAttribute("href") is the relative url to the page. See this fiddle.
The problem with your code is that the var is captured in the closure of onclick and when the onclick function runs the value will of i will be anchors.length.
Solution, Scratch that use the code from Johannes H. His is better
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
(function () {
var current = anchors[i]; //Capture the anchor element
current.onclick = function() {
var link = current.getAttribute("href");
};
} ());
}

See this w3 schools page for how to get the href attribute from anchor tags.
http://www.w3schools.com/jsref/prop_anchor_href.asp
var anchors = document.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++)
{
anchors[i].onclick = function() {
if (anchors == null) {
alert('null');
}
else {
var link = this.href;
}
}
}

Related

Why can't I remove my event listener?

I have an issue with removeEventListener, it doesn't seem to work at all, I've seen some other questions on this site but I don't get it, can you help me?
displayImg() {
console.log('img')
for (var i = 1; i <= 4; i++) {
var line = "l"+i;
var position = 0;
var addDivLine = document.createElement('div');
addDivLine.className = 'line';
addDivLine.id = line;
document.getElementById('container').appendChild(addDivLine);
for (var j = 1; j <= 7; j++) {
var block = "b"+j;
var element = line+"-"+block;
var addDivBlock = document.createElement('div');
addDivBlock.className = 'block';
addDivBlock.id = element;
document.getElementById(line).appendChild(addDivBlock);
memory.addEvent(element);
};
};
showImage(event) {
event.preventDefault();
memory.clickedBlock++;
var block = event.target.id;
memory.removeEvent(block);
}
addEvent(id){
document.getElementById(id).addEventListener('click', function(){memory.showImage(event)});
},
removeEvent(id){
console.log("remove");
document.getElementById(id).removeEventListener('click', function(){memory.showImage(event)});
},
I am creating div elements then put an eventListener on them, I call the same function to remove the event, I use the same id, is there something that I forgot? I probably don't fully understand how it really works.
Thanks a lot!
In this two lines:
.addEventListener('click', function() { memory.showImage(event) });
and
.removeEventListener('click', function() { memory.showImage(event) });
function() { memory.showImage(event) } are two different functions. You need to provide reference to the same function in both cases in order to bind/unbind listener. Save it so some variable and use in both places:
.addEventListener('click', memory.showImage);
.removeEventListener('click', memory.showImage);
For example using directly memory.showImage will work properly as it's the same function in both cases.
The function looks like the same but its reference would be different. So, define the function in a scope where it's available for both function and use the reference in both case.
var callback = function(){memory.showImage(event)};
addEvent(id){
document.getElementById(id).addEventListener('click', callback);
}
removeEvent(id){
console.log("remove");
document.getElementById(id).removeEventListener('click', callback);
}

Get the specific div id from an onclick event (Pure JS no Jquery)

When I try the code referenced in SO #1, I get the console logging a blank string:
installChoices() {
var choices = this.game.page.options;
for (var i = 0; i < choices.length; i++) {
var choice = choices[i];
var choiceDiv = document.createElement("choice" + i);
choiceDiv.innerText = choice[0];
choiceDiv.onclick = function() {
console.log(this.id);
}
this.choicesContainer.appendChild(choiceDiv);
}
}
I want to bind to my class function clicked
installChoices() {
var choices = this.game.page.options;
for (var i = 0; i < choices.length; i++) {
var choice = choices[i];
var choiceDiv = document.createElement("choice" + i);
choiceDiv.innerText = choice[0];
choiceDiv.onclick = this.clicked;
this.choicesContainer.appendChild(choiceDiv);
}
}
clicked(e) {
console.log(e.parentNode); //this is undefined
console.log(e.srcElement);
}
But that shows undefined. When I log srcElement, I get the full element
<choice0>path 1</choice0>
I want to get just the div id when I click, so I can parse that and do logic.
I'd recommend the following approach, as it is the standard:
//assign the event
choiceDiv.addEventListener('click', clicked)
//define the listener
function clicked(event) {
console.log(event.currentTarget)
}
update:
I'm tempted to offer a fix to your code, because I don't think you're achieving what are you trying to actually do:
function installChoices() {
var choices = this.game.page.options;
for (var i = 0; i < choices.length; i++) {
var choice = choices[i];
var choiceDiv = document.createElement("div");
choiceDiv.id = "choice" + i;
choiceDiv.innerText = choice[0];
choiceDiv.addEventListener("click", clicked);
this.choicesContainer.appendChild(choiceDiv);
}
}
function clicked(ev) {
console.log(ev.currentTarget.id); //this will log "choice0"
}
Your "clicked" function are receiving an Event rather than a HTML Element. This is the default behavior when an onClick event triggered.
The click event have a srcElement property, indicating the source element the click event occurred upon. This event object have no parentNode property.
Use e.srcElement.parentNode instead.
BTW, in the SO #1 example, it assign "showIt(this)" to onClick, so browser pass "this", the target element rather than the event object, to the onClick function.

How to open all links on a mouseover event in javascript?

I tried this:
for (i = 0; i < document.getElementsByTagName('a').length; i++) {
document.getElementsByTagName('a')[i].onmouseover= eval(function(){
window.open(document.getElementsByTagName('a')[i].href, "_blank");});
}
But it went wrong when reaching this part of the code: "window.open(document.getElementsByTagName('a')[i].href"
"Uncaught TypeError: Cannot read property 'href' of undefined "
EDIT 1:
I also tried this:
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onmouseover = function(){window.open(links[i].href, "_blank")};
}
I got the same error: Uncaught TypeError: Cannot read property 'href' of undefined
When I change 'i' to 'i-1' for window.open every single link gets replaced with the last link on the page, see code:
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onmouseover = function(){window.open(links[i-1].href, "_blank")};
}
This should work as expected:
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
links[i].onmouseover = (
function(h){
return function(){ window.open(h, "_blank") }
}
)(links[i].href);
}
Why you are getting Unable to get href of ...... is because the element is probably because the element is not YET defined. This means you should put the code at the end or add it to window.onload - using addEventListener instead of onload.
Well, #Arnauld's answer is probably good enough, but I suggest to use addEventListener and attachEvent, because it can probably make your coding easier :)
var links = document.getElementsByTagName("a");
for (var i = 0; i < links.length; i++){
if(links[i].addEventListener){ // Check if addEventListener is available
links[i].addEventListener("mouseover", function(){
window.open(links[i].href, "_blank");
});
}else{
if(links[i].attachEvent){ // addEventListener not available; test attachEvent
links[i].attachEvent("onmouseover", function(){
window.open(links[i].href, "_blank");
});
}else{
// Neither attachEvent nor addEventListener is available; Throw error (You can try to use links[i].onmouseover)
throw new Error("!(addEventListener & attachEvent)");
}
}
}

Javascript IE8 wrapper for existing onclick event

I have to call another function before the original onclick event fires, I've tried a lot of different paths before I've come to following solution:
function bindEnableFieldToAllLinks() {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
var link = links[i];
var onclick = link.getAttribute('onclick');
link.onclick = new Function("if(linkClickHandler()){"+onclick+"}");
console.log(link.getAttribute('onclick'));
}
}
This does the trick in Firefox and Chrome but IE8 is acting strange, it seems that the function that's in the onclick variable isn't executed.
I've already added console.log messages that get fired after the if statement is true and if I print out the onclick attribute I get following:
LOG: function anonymous() {
if(linkClickHandler()){function onclick()
{
if(typeof jsfcljs == 'function'){jsfcljs(document.getElementById('hoedanigheidForm'), {'hoedanigheidForm:j_id_jsp_443872799_27':'hoedanigheidForm:j_id_jsp_443872799_27'},'');}return false
}}
}
So it seems that the function is on the onclick of the link and the old onclick function is on it as well.
Can anyone help me out with this please?
Say you have an onclick attribute on a HTMLElement..
<span id="foo" onclick="bar"></span>
Now,
var node = document.getElementById('foo');
node.getAttribute('onclick'); // String "bar"
node.onclick; // function onclick(event) {bar}
The latter looks more useful to what you're trying to achieve as using it still has it's original scope and you don't have to re-evaluate code with Function.
function bindEnableFieldToAllLinks() {
var links = document.getElementsByTagName('a'),
i;
for (i = 0; i < links.length; i++) function (link, click) { // scope these
link.onclick = function () { // this function literal has access to
if (linkClickHandler()) // variables in scope so you can re-
return click.apply(this, arguments); // invoke in context
};
}(links[i], links[i].onclick); // pass link and function to scope
}
Further, setting a named function inside an onclick attribute (i.e. as a String) doesn't achieve anything; the function doesn't invoke or even enter the global namespace because it gets wrapped.
Setting an anonymous one is worse and will throw a SyntaxError when onclick tries to execute.
This will do what you want, executing what is inside linkClickHandler first, and then executing the onclick event. I put in a basic cross browser event subscribing function for your reuse.
bindEnableFieldToAllLinks();
function bindEnableFieldToAllLinks() {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
var link = links[i];
var onclick = link.getAttribute('onclick');
onEvent(link, 'click', function() {
linkClickHandler(onclick);
});
link.onclick = undefined;
}
}
function onEvent(obj, name, func) {
if (obj.attachEvent) obj.attachEvent('on' + name, func);
else if (obj.addEventListener) obj.addEventListener(name, func);
}
function linkClickHandler(funcText) {
alert('before');
var f = Function(funcText);
f();
return true;
}
jsFiddle

JavaScript closure for jQuery event handler

I have a list of objects each of which has a .bullet which is a SPAN. I want to bind a click on the span to a handler than performs a certain action on the span using jQuery. I'm seeing some behavior I don't understand, so I'm hoping someone can explain what's going on. Basically, this first code example works:
for (var i = 0 ; i< length ; i++) {
(function(){
dataNode = dataNodeList[i];
var handler = function(e) {
e.data.node.bullet.firstChild.nodeValue = "- ";
};
$(dataNode.bullet).on("click",{node:dataNode},handler);
})();
}
However, this second variation does not work:
for (var i = 0 ; i< length ; i++) {
(function(){
dataNode = dataNodeList[i];
var handler = function() {
dataNode.bullet.firstChild.nodeValue = "- ";
};
$(dataNode.bullet).on("click",handler);
})();
}
In this second example,
dataNode.bullet.firstChild.nodeValue = "- ";
has no effect on the value of the SPAN I intended. I expected dataNode.bullet to still point to the SPAN I want to change because of JavaScript closure. So, can someone explain why this fails? Thanks.
Try this:
for (var i = 0 ; i< length ; i++) {
(function(index){
var dataNode = dataNodeList[index];
var handler = function() {
dataNode.bullet.firstChild.nodeValue = "- ";
};
$(dataNode.bullet).on("click",handler);
})(i);
}
The closure defines a new scope. This is necessary because your handler isn't called until after the loop has finished, so i is not part of the scope at the time it is called, or (in some cases) has the last possible value from the loop.

Categories

Resources