Set onclick of <a> using JavaScript - javascript

I want to change all the links in a div such that they no longer refer to a page, but run a JavaScript function when being clicked. To do so, I wrote this function:
function buildPageInDiv(htmlString){
console.log(typeof htmlString);
$div = $(htmlString).children("div#myDiv");
$div.children("a").each(function(i, element){toJavascriptLinks(element)});
document.getElementById("targetDiv").innerHTML = $div[0].innerHTML;
}
calling this function:
function toJavascriptLinks(element){
element.href="#";
element.onclick = function(){console.log('Yeah!')};
console.log(element);
}
Now, when I run buildPageInDiv, 'string' is printed on the console, all the "href" are changed to "#" and for every <a> within the div the console prints the element:
<a href="#">
No sign of the onclick here, and clicking on the link does not show anything on the console.
What am I missing here?
Edit:
I was seeking in the wrong place. The problem was that I was running toJavascriptLinks(element) before attaching the innerHTML to targetDiv. That was no problem for the href attribute, but it was for the onclick attribute. Solution is simply to put it in targetDiv first and than run toJavascriptLinks(element) on targetDiv :
function buildPageInDiv(htmlString){
console.log(typeof htmlString);
var content = $(htmlString).children("div#myDiv")[0].innerHTML;
document.getElementById("targetDiv").innerHTML = content;
$("div#targetDiv").children("a").each(function(i, element) toJavascriptLinks(element)});
}
Although the problem was not in the code I originally posted, the comprehensive answers below led me to the solution.

First: All type of selectors in jQuery, start with the dollar sign and parentheses: $()
Secondly: you need to close your statements with ;
Lastly: it is good practice to define your functions BEFORE you call them, instead of relying on javascript to hoist them to the top for you. This will also make jslint validate, whereas the other way round wouldn't!
So your code without your errors would look like:
function toJavascriptLinks(element){
element.href="#";
element.onclick = function(){alert('Yeah!');};
console.log(element);
}
$('div').children("a").each(function(i, element){toJavascriptLinks(element);});
See this fiddle for a working demo.
Good Luck!!
ABOUT YOUR UPDATED QUESTION:
That's quite an update to your question.
You don't see your onclick in console.log because you set the onclick event in the dom. If you wanted to see the onclick in console.log, you would add the function STRING using:
element.setAttribute('onclick', 'your function string');
Suppose in your html you have:
<a id="link_a" href="http://www.google.com">link 1</a>
<a id="link_b" href="http://www.duckduckgo.com">link 2</a>
And you have this javascript:
var lnkA=document.getElementById("link_a");
var lnkB=document.getElementById("link_b");
lnkA.onclick=function(){alert(this.innerHTML);};
lnkB.setAttribute('onclick','alert(this.innerHTML);');
console.log(lnkA.outerHTML);
console.log(lnkB.outerHTML);
Then console.log will contain:
<a id="link_a" href="http://www.google.com">link 1</a>
<a onclick="alert(this.innerHTML);" id="link_b" href="http://www.duckduckgo.com">link 2</a>
See this fiddle for a live example of this explanation.
I also think you are already using some form of jQuery (without you knowing it) because of your use of .children("div#myDiv"). To my knowledge this no plain vanilla javascript. And I think both plain vanilla javascript and jQuery would not select those divs with id 'myDiv' out of a plain html-string, so the code in your update would not do the job.
Finally, to adjust my answer to your updated question and expectation of the onclick-event being visible in the parsed html-source:
var htmlString='<div id="myDiv">link 1link 2</div><div id="otherDiv">link 3link 4</div>';
function toJavascriptLinks(element){
element.href="#";
element.setAttribute('onclick','console.log("Yeah!");');
console.log(element.outerHTML);
}
//no innerHTML on documentFragment allowed, yet on it's children it's allowed
var frag = document.createDocumentFragment().appendChild( document.createElement('div') );
frag.innerHTML=htmlString;
var $div = $(frag).children('div#myDiv');
$($div).children("a").each(function(i, element){toJavascriptLinks(element);});
var outp=document.getElementById("output");
outp.innerHTML=frag.innerHTML;
See this updated fiddle to see it in action.
That leaves the question: why on earth are you placing 'ninja' $-signs front of your variable names?

That's just the way the debugger displays an HTML element. It doesn't show all attributes - especially since you are setting the DOM property onclick to a function reference, which can't be displayed as the HTML attribute onclick which takes a string (which AFAIK can't be set with JavaScript see Luc's comment).
Try console.log(element.onclick); instead, it should display something like function() {...}.
Or doesn't the event handle work?
BTW, any reason you don't use jQuery to set the href and the handler?
$div.children("a").attr('href', '#').click(function(){console.log('Yeah!')});
One more thing: In most consoles you can click on <a href="#"> and it will display the DOM properties, which should include the event handler.

I would really use jQuery for this, it's quite simple.
​$(function() {
$("div > a ").attr("href", "#").click(function(e) {
e.preventDefault();
doSomething();
});
});
var doSomething = function() {
alert("Woah, it works!");
}
See the following jsfiddle for it in action: http://jsfiddle.net/SsXtt/1/

Are you sure the element is correct? This works for me.
<a id="mylink">Test</a>
<script>
document.getElementById("mylink").onclick = function() {
alert("Works");
};
</script>

Function needs to be inside a string, try adding quotes?

Related

Undefined DOM element javascript, while console.log gives it out

I'm quite new in javascript and this problem is haunting me down since the very begining. When I get DOM element event behaves properly, but while I try to change anything (like class) it gives me "undefined is not a function".
I don't understand why, because in the same time console.log gives out
<div class="nav-about menu" id="nav-about"></div>
HTML
<div class="nav-about menu" id="nav-about"></div>
JS
var link_one = document.getElementById("nav-about");
link_one.addEventListener("click", function(){
console.log(this);
this.addClass('special');
}, false);
I couldn't find answer to that anywhere. Yes jquery to addClass is included in head tag.
Because there is no addClass property on this, so it's undefined.
You could add the class on this.classList.
var link_one = document.getElementById("nav-about");
link_one.addEventListener("click", function(){
this.classList.add('special');
}, false);
try
$(this).addClass('special');
because you want to use jquery library, to use jquery library is like calling a function doSomething(this), but instead use $ as the function name

jquery show another link then hide itself

I have this following jquery on my view:
$(document).ready(function() {
$(function() {
$('#link1').click(function() {
$('#link2').show();
$('#link1').hide();
$('#frame').attr('src', 'http://google.com/');
});
});
});
$(document).ready(function() {
$(function() {
$('#link2').click(function() {
$('#link1').show();
$('#link2').hide();
$('#frame').attr('src', 'http://yahoo.com/');
});
});
});
On pageload, the link2 is set to hide. What the jQuery does is: when the link with id link1 is clicked, it will show the link with idlink2 and hide itself. And vice versa.
My problem is it seems that my jQuery code can still be simplified. Is there other ways I can do what I wanted with simpler version? Thanks for the help!
Working example : http://jsfiddle.net/cuJBm/
$(document).ready(function() {
$(function() {
var linkSet = $('#link1').add('#link2')
linkSet.click(function() {
linkSet.toggle();
});
});
});
The add method allows you to add a different selector to the set of matchers, thus binding both clicks simultaneously. By saving the constructed set to a variable (linkSet), it stops you from having to traverse the DOM twice.
The only two assumption made here, are
1) That in the initial state only one is visible.
2) That the id structure is meaningful, useful, and classes will not suffice.
http://jsfiddle.net/cuJBm/1/
To answer your second question about setting an attribute on #frame. There are numerous ways of doing this. Perhaps the simplest is to add the following to your .click handler (after the toggle).
if ($(this).attr('id')=='link1'){
$('#frame').attr('src', 'www.google.com');
} else if ($(this).attr('id')=='link2'){
$('#frame').attr('src', 'www.yahoo.com');
}
Personally, I would probably add a custom attribute to your link elements, something like:
<a id='link1' iframe-source='www.google.com'>
<a id='link2' iframe-source='www.yahoo.com'>
And then: (again, just after the toggle):
source = $(this).attr('iframe-source');
$('#frame').attr(src, source);
The reason for saving source if is that if you attempt to get $(this) within the .attr on $('frame'), it will (as always) return the currently matched element, ie $('#frame').
Alternately (and very similiarly to the above approach), you could use the innerHTML of the link. For example:
<a id='link1'>link1<span style="display:none">www.google.com</span></a>
<a id='link2'>link2<span style="display:none">www.yahoo.com</span></a>
And then: (again, just after the toggle):
source = $(this).find('span').text();
$('#frame').attr(src, source);
Personally, I dislike this last method as it pollutes the DOM structure, leading to slightly more expensive rendering times, and (in my opinion) less readable code. Practically, all three methods work just fine.
<p class="link" style="display:none;" data-link="http://google.com/">sfdf</p>
<p class="link" data-link="http://yahoo.com/">ee</p>
$('.link').click(function() {
$('.link').toggle();
$('#frame').text($(this).data("link"));
});
jsfiddle :http://jsfiddle.net/xqDus/1/
Use jQuery toggle()
just add this
Google
Yahoo
target is id of the frame
$(function() {
$('#link1, #link2').click(function() {
$('#link1, #link2').toggle();
});
});

javascript onclick failing on a function call

I have this html...
<a onclick="search.analysisSelect('2');" href="javascript:void(0);">A Product</a>
...And whenever I click that link in the browser (IE, FF, and Chrome), it fails. It tells me that the function does not exist. However, if I type that exact function call into the console of firebug, it runs fine. So the function does exist.
Exact error message: "search.analysisSelect is not a function"
I have recently changed the "search" object name to "searchTab" and the onclick works fine.
Why is the onclick failing for the search object? I am baffled...
Here is the search object. This is stored in a separate js file loaded when the page loads.
var search = {
analysisSelect: function(pub) {
$("#tabs").tabs("select", "#analysis");
analysisGrid.refreshSlickGrid(pub, '0', '1', '0');
}
};
Oh, I forgot to mention that I also have an init() funciton defined in the search object, which is called on an onclick event for another html element, and that fires off with no issues. Wtf...
Where did you define search.analysisSelect()? It should be defined before the anchor tag.
generally using inline javascripts is not a good idea, consider using an external javascript file and bind that function to the anchor onclick event like this:
window.onload = function() { // ensures that the document is loaded before finding the anchor element
// assign an Id to the anchor tag like this: <a id="idOfAnchorTag" href="#">A Product</a>
var elem = getElementById('idOfAnchorTag');
elem.onclick = function() {
search.analysisSelect('2');
}
}
There is some strange javascript voodoo going on in the inline event handler. search is not being resolved to window.search, it is hitting something else and I don't know what it is.
See http://jsfiddle.net/yPhZ8/
However, I can tell you how to fix it. Use window.search instead.
<a onclick="window.search.analysisSelect('2');" href="javascript:void(0);">A Product</a>
See: http://jsfiddle.net/yPhZ8/1/
I just had this exact problem today. Turns out, you can't have an HTML element with an ID the same as the function.
Don't ask me why, I'd just say it has something to do with extremely lazy parsing.
My Example:
<dd style="margin-left: 2px;"><input type="button" name="info[add_benefit]" id="add_benefit" value="{L_ADD_BENEFIT}" class="button2"
style="width: 100%;" onclick="add_benefit();" /> </dd>
The onclick method would return an error saying that the function didn't exist. Apparently it thought the button itself was the function, but the button was a button, hence the error.

Executing JavaScript when a link is clicked

Which is preferable, assuming we don't care about people who don't have JavaScript enabled?
Or
Is there any difference?
Or there any other ways I'm missing besides attaching an event to the anchor element with a JavaScript library?
The nice thing about onclick is you can have the link gracefully handle browsers with javascript disabled.
For example, the photo link below will work whether or not javascript is enabled in the browser:
foobar
it's better to use the onclick because that's the way the things should be.
The javascript: was somekind of hackish way to simulate the onclick.
Also I advice you to do some non intrusive Javascript as much as possible, it make the code more easy to read and more maintainable!
href="#" has a number of bad side effects such as showing # in the browser footer as the destination URL, and if the user has javascript disabled it will add a # at the end of their URL when they click the link.
The best method IMHO is to attach the handler to the link in your code, and not in the HTML.
var e = document.getElementById("#myLink");
e.onclick = executeSomething;
This is essentially the pattern you'd want to follow:
Write your HTML markup
Attach event handlers from JavaScript
This is one way:
<a id="link1" href="#">Something</a>
<script type="text/javascript">
// get a reference to the A element
var link1 = document.getElementById("link1");
// attach event
link1.onclick = function(e) { return myHandler(e); };
// your handler
function myHandler(e) {
// do whatever
// prevent execution of the a href
return false;
}
</script>
Others have mentioned jQuery, which is much more robust and cross-browser compatible.
Best practice would be to completely separate your javascript from your mark up. Here's an example using jQuery.
<script type="text/javascript">
$(function() {
$('a#someLink').click( function() {
doSomething();
return false;
});
});
</script>
...
some text
Yes I would agree to use onclick and leave the href completely out of the anchor tag... Don't know which you prefer to do but I like to keep the 'return false' statement inside by function as well.
The main difference is that:
The browser assume by default the href attribute is a string (target url)
The browser knows that in a onclick attribute this is some javascript
That's why some guys specify to the browser "hey, interpret javascript when you read the href attribute for this hyperlink" by doing ...
To answer the question, that's the difference!
OTOH what's the best practice when using javascript events is another story, but most of the points have been made by others here!
Thanks

JavaScript: changing the value of onclick with or without jQuery

I'd like to change the value of the onclick attribute on an anchor. I want to set it to a new string that contains JavaScript. (That string is provided to the client-side JavaScript code by the server, and it can contains whatever you can put in the onclick attribute in HTML.) Here are a few things I tried:
Using jQuery attr("onclick", js) doesn't work with both Firefox and IE6/7.
Using setAttribute("onclick", js) works with Firefox and IE8, but not IE6/7.
Using onclick = function() { return eval(js); } doesn't work because you are not allowed to use return is code passed to eval().
Anyone has a suggestion on to set the onclick attribute to to make this work for Firefox and IE 6/7/8? Also see below the code I used to test this.
<html>
<head>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var js = "alert('B'); return false;";
// Set with JQuery: doesn't work
$("a").attr("onclick", js);
// Set with setAttribute(): at least works with Firefox
//document.getElementById("anchor").setAttribute("onclick", js);
});
</script>
</head>
<body>
Click
</body>
</html>
You shouldn't be using onClick any more if you are using jQuery. jQuery provides its own methods of attaching and binding events. See .click()
$(document).ready(function(){
var js = "alert('B:' + this.id); return false;";
// create a function from the "js" string
var newclick = new Function(js);
// clears onclick then sets click using jQuery
$("#anchor").attr('onclick', '').click(newclick);
});
That should cancel the onClick function - and keep your "javascript from a string" as well.
The best thing to do would be to remove the onclick="" from the <a> element in the HTML code and switch to using the Unobtrusive method of binding an event to click.
You also said:
Using onclick = function() { return eval(js); } doesn't work because you are not allowed to use return in code passed to eval().
No - it won't, but onclick = eval("(function(){"+js+"})"); will wrap the 'js' variable in a function enclosure. onclick = new Function(js); works as well and is a little cleaner to read. (note the capital F) -- see documentation on Function() constructors
BTW, without JQuery this could also be done, but obviously it's pretty ugly as it only considers IE/non-IE:
if(isie)
tmpobject.setAttribute('onclick',(new Function(tmp.nextSibling.getAttributeNode('onclick').value)));
else
$(tmpobject).attr('onclick',tmp.nextSibling.attributes[0].value); //this even supposes index
Anyway, just so that people have an overall idea of what can be done, as I'm sure many have stumbled upon this annoyance.
One gotcha with Jquery is that the click function do not acknowledge the hand coded onclick from the html.
So, you pretty much have to choose. Set up all your handlers in the init function or all of them in html.
The click event in JQuery is the click function $("myelt").click (function ....).
just use jQuery bind method !jquery-selector!.bind('event', !fn!);
See here for more about events in jQuery
If you don't want to actually navigate to a new page you can also have your anchor somewhere on the page like this.
<a id="the_anchor" href="">
And then to assign your string of JavaScript to the the onclick of the anchor, put this somewhere else (i.e. the header, later in the body, whatever):
<script>
var js = "alert('I am your string of JavaScript');"; // js is your string of script
document.getElementById('the_anchor').href = 'javascript:' + js;
</script>
If you have all of this info on the server before sending out the page, then you could also simply place the JavaScript directly in the href attribute of the anchor like so:
Click me
Note that following gnarf's idea you can also do:
var js = "alert('B:' + this.id); return false;";<br/>
var newclick = eval("(function(){"+js+"});");<br/>
$("a").get(0).onclick = newclick;
That will set the onclick without triggering the event (had the same problem here and it took me some time to find out).
Came up with a quick and dirty fix to this. Just used <select onchange='this.options[this.selectedIndex].onclick();> <option onclick='alert("hello world")' ></option> </select>
Hope this helps

Categories

Resources