3

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.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jos
  • 1,015
  • 2
  • 13
  • 25

5 Answers5

6

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"><a href="http://www.google.com">link 1</a><a href="http://www.duckduckgo.com">link 2</a></div><div id="otherDiv"><a href="http://www.asdf.com">link 3</a><a href="http://www.yahoo.com">link 4</a></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?

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
  • Thanks for you answer, but I have been onclear. Before $div, there is the line: var $div = $(htmlResponse).children("div#idOfDiv"); htmlResponse is some variable containg html to parse. I will update the question – Jos Aug 17 '12 at 12:37
  • @GitaarLAB have you hared about Hoisting? :) – Zango Aug 17 '12 at 12:45
  • @Zango: Yes, that's why defining your functions before you call them is a good practice. And it makes jslint validate. Or what did I miss? – GitaarLAB Aug 17 '12 at 12:46
  • Mm, thanks for the demo. Works perfectly there :). I go into it. – Jos Aug 17 '12 at 12:49
  • @GitaarLAB http://jsfiddle.net/ak7pk/2/ In this case you do not "need to define your functions BEFORE you call them!". If you haven't hared about JavaScript Hoisting read about it... – Zango Aug 17 '12 at 12:52
  • @Zango: hehe, [your update](http://jsfiddle.net/ak7pk/2/) on my fiddle proves my point on jslint not validating, while proving your point that it is not mandatory. That being said, I can understand that it's the word 'need' you have problems with, since it is not strictly needed for javascript to work due to hoisting. I'll update my answer. – GitaarLAB Aug 17 '12 at 13:04
  • @Jos: Updated my answer to address your updated question. Please don't forget to accept an answer eventually! – GitaarLAB Aug 17 '12 at 17:21
  • @GitaarLAB Thanks for the really comprehensive answer, it put me really on the solution, and brought me a lot of understanding (and realizing there is a lot I do not understand of javascript/jquery). One thing remains: "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." It seems that Jquery is capable of doing that, or I am (again) missing something. – Jos Aug 18 '12 at 09:57
  • You don't need to close statements with a semicolon at all. – jocap Aug 18 '13 at 19:22
  • @jocap: not 'closing' statements 'at all' is such an overly broad statement that it is wrong! In reality 'it depends' (way to difficult for a newbie). Think about it: the name of the feature 'automatic semicolon insertion' already implies that (at least some of) the semicolons should have been there in the first place. There are numerous examples where this feature fails! The same goes for a 'compiler'/translator: be unambiguous in what you want, don't make it guess. Also read http://stackoverflow.com/questions/444080/do-you-recommend-using-semicolons-after-every-statement-in-javascript – GitaarLAB Aug 28 '13 at 10:17
  • @GitaarLAB: There is only one case where a semicolon is necessary, and it's when you start a line with a parenthesis. All other times the semicolons changes exactly *nothing*. It's not too difficult for a newbie. – jocap Sep 09 '13 at 22:45
  • I'll agree that "at all" was confusing. I meant to contradict you. – jocap Sep 09 '13 at 22:46
2

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.

RoToRa
  • 37,635
  • 12
  • 69
  • 105
  • 1
    _"(and which AFAIK can't be set with JavaScript)"_ element.setAttribute("onclick", "alert('WFM');"); – Luc Aug 17 '12 at 12:38
  • Thanks for your answer. The reason for not doing the JQuery stuff is that I am not an expert and simply did not know. Thanks for teaching me. Regretfully, both of your proposals did not bring the solution for me. – Jos Aug 17 '12 at 12:43
1

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/

sQVe
  • 1,977
  • 12
  • 16
0

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>
Luc
  • 5,339
  • 2
  • 48
  • 48
-1

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

ddoor
  • 5,819
  • 9
  • 34
  • 41
  • Doesn't need to be, an anonymous function does the job too. Moreover, assigning a string only works with element.setAttribute(). – Luc Aug 17 '12 at 12:28