9

Here is my situation. I have some links throughout a website. Some of them look like this:

<a target="_blank" onclick="someFunction()" href="/somFile.pdf">some file</a>

and some look like this:

<a target="_blank" href="/somFile.pdf">some file</a>

All of the links should be calling someFunction() when clicked. The ones that have the call in the onclick attribute are legacy content pages. Newer pages have a jQuery click event attached to them like so:

$(document).ready(function(){
  $('a[href$=".pdf"]').click(function() {
    someFunction();
  });
});

So here's the thing. I can update someFunction(), but I cannot touch the actual links or that jQuery. What I need is to know the href value of the link clicked. I have tried using the following within someFunction() :

var ev = window.event;
origEl = ev.target || ev.srcElement;
console.log(origEl.href);

but this does not work. I also tried console.log(window.event) and get nothing, says it is undefined. Any idea what I'm missing here, or is it basically impossible without passing a reference to it when the function is called?

edit: to be clear, I cannot as a short or even medium term solution edit the call to someFunction() in the onclick or in the jQuery code black, so I cannot for instance change them to someFunction(this) or similar. I'm not sure it is possible to get the href from within someFunction() unless I do that though :(

slinkhi
  • 947
  • 4
  • 16
  • 32
  • My fiddle works as you requested. I did have to modify your code blocks, but ONLY to prevent the link from actually trying to get something, and to conform the rest of the code accordingly due to the missing pdf reference link. – Lazerblade Apr 16 '12 at 23:55

5 Answers5

13

Here it is in PURE JavaScript

    //assuming links inside of a shared class "link"
    for(var i in document.getElementsByClassName('link')) {
        var link = document.getElementsByClassName('link')[i];

        link.onclick = function(e) { 
            e.preventDefault();

            //using returned e attributes
            window.location = e.srcElement.attributes.href.textContent;     
        } 
    } 

    //tested on Chrome v31 & IE 11
    //not working in Firefox v29
    //to make it work in all browsers use something like:

    if (e.srcElement === undefined){
    //scrElement is undefined in Firefox and textContent is depreciated

      window.location = e.originalTarget.attributes.href.value;
    } else {
      window.location = e.srcElement.attributes.href.textContent;
    }

    //Furthermore; when you setAttribute("key" "value"); 
    //you can access it with the above node link. 
    //So say you want to set an objectId on something     
    //manually and then grab it later; you can use 

    //Chrome & IE
    //srcElement.attributes.objectid.textContent; 

    //Firefox
    //e.originalTarget.attributes.objectid.value;

    //*Note: for some unknown reason the attribute being defined as "objectId" is changed to "objectid" when it's set.
Ryan Alexander
  • 569
  • 5
  • 9
10

You don't need anything other than this.href inside of the click callback.

$(document).ready(function()
{    
    function someFunction(foo)
    {
        console.log(foo);
    }

    $('a[href$=".pdf"]').click(function()
    {
        someFunction(this.href);
    });
});

Alternately, you can make this point to the <a> even inside of someFunction, like so:

$(document).ready(function()
{    
    function someFunction()
    {
        console.log(this.href);
        console.log(event);
    }

    $('a[href$=".pdf"]').click(someFunction);
});

or if that doesn't suit you, we can get fancier with Function.apply:

$(document).ready(function()
{    
    function someFunction(event)
    {
        console.log(this.href);
        console.log(event);
    }

    $('a[href$=".pdf"]').click(function (event)
    {
        someFunction.apply(this, event);
    });
});
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • OP said he can't touch the click function. He said has to do it in javascript but without making changes to the top 2 sections of code. – Lazerblade Apr 16 '12 at 23:36
  • It was not completely clear _exactly_ what cannot be changed about the jQuery code. If nothing can be changed, then it cannot be done. – Matt Ball Apr 16 '12 at 23:39
  • right...I cannot change anything in the jQuery codeblock or the onclick call.. so I can't just do `someFunction(this);` Also, I tried doing `console.log(this.href);` inside someFunction() and it too gave me 'undefined' – slinkhi Apr 16 '12 at 23:46
  • I beg to differ. See my answer. – Lazerblade Apr 16 '12 at 23:56
  • @mysql_noobie_xxxx (addendum to my prior comment): you cannot access the clicked element's `href` value in `someFunction` in a cross-browser-compatible manner without changing **something** in the jQuery code block. – Matt Ball Apr 17 '12 at 00:34
  • yeah..so if I am able to change the jQuery code or onclick call...i can pass an object reference easy enough. The problem is that I have a client that is willing to let me change this function within a javascript file, but is unwilling at this time to change the jQuery selector or onclick call that is on-page, unwilling to let me change anything outside this function at this time :( – slinkhi Apr 17 '12 at 01:20
  • @mysql_noobie_xxxx your client sounds foolish, unreasonable, and stubborn. If they know better than you, why aren't they doing it themselves? – Matt Ball Apr 17 '12 at 01:21
  • It's not that they are foolish or unreasonable..it's mostly a matter of resources. I can supply them with a new version of the function and they can apply in 2s easy enough because it is in some global file. But to change the on-page code on all of their pages...will require a lot more work..something they "cannot" do at this time. Now...why they hardcoded a bunch of random links and individually hardcoded the jquery code on a bunch of pages in the first place...lol maybe there is a bit of foolishness on their part, as they are now having to throw the "easy" options out the door. – slinkhi Apr 17 '12 at 01:25
  • 1
    well anyways, I gave a +1 for effort, guess I will just need to tell the client to suck it, no joy until they do what needs to be done :/ – slinkhi Apr 17 '12 at 01:28
  • 1
    @mysql_noobie_xxxx so it goes with legacy code. I live this daily. – Matt Ball Apr 17 '12 at 01:31
1

Use either this.href, or the more jQuery appropriate $(this).attr('href') to get the value of each of your links.

Seabass
  • 1,963
  • 12
  • 15
  • 3
    There is absolutely no need to use `.attr()` in this case. `this.href` works in all browsers, and has better performance, and is significantly more concise. http://stackoverflow.com/a/4652402/139010 – Matt Ball Apr 16 '12 at 23:35
  • @MДΓΓБДLL: I was under the impression that 'older' versions of IE (though I can't recall *which* versions) required `this.getAttribute('href')` rather than the simple `this.href`? Sorry I can't provide support for this understanding, though...just one of those things I've believed for so long, I guess. =/ – David Thomas Apr 16 '12 at 23:37
  • @DavidThomas I could be wrong, since I use that answer as reference but have not tested it myself (I run OS X at work and home, and a VM is quite simply not worth the effort). – Matt Ball Apr 16 '12 at 23:40
  • 1
    @MДΓΓБДLL: what can I say? 'S a *good* reference..! Though I'm still curious. Perhaps a job for tomorrow, then. Or...whenever I next remember about it. – David Thomas Apr 16 '12 at 23:44
  • Ah, I recommended $(this).attr('href') since I remember this.href throwing undefined errors in early versions of IE. – Seabass Apr 16 '12 at 23:46
  • 1
    I added `console.log(this.href);` inside someFunction() and it said 'undefined' :( – slinkhi Apr 16 '12 at 23:47
1

So I let this simmer for a while and I did come up with a short term solution...it's pretty hacky and I feel kinda dirty for doing it but sometimes you just gotta do what you gotta do until you can do what you need to do... anyways, I'm posting my ugly solution here for others who might be backed into a similar corner...

Keep in mind, the only code I'm allowed to touch in OP is the someFunction() function itself. Also, I can add some extra code in the same place as where it located, which is what I have done...

Basically the solution is to make an additional click listener that puts the href value into a variable exposed to the function, and hen wrap the someFunction() code in a small timeout to make sure the new click function can do its thing..

<!-- STUFF I CAN'T TOUCH! (located on-page) -->
<a target="_blank" onclick="someFunction()" href="/somFile.pdf">some file</a>
<a target="_blank" href="/somFile.pdf">some file</a>

<script type='text/javascript'>
$(document).ready(function(){
  $('a[href$=".pdf"]').click(function() {
    someFunction();
  });
});
</script>
<!-- END STUFF I CAN'T TOUCH! -->

/*** STUFF I CAN TOUCH! (located in a script include) ***/
// hackjob!
$(document).ready(function(){
  $('a').click(function() {
    if ($(this).attr('href')) someFunction.href = $(this).attr('href');
  });
});

function someFunction(a) {
  // more hackjob!
  window.setTimeout("console.log(someFunction.href);",200);
}
/*** END STUFF I CAN TOUCH!***/

So anyways, yeah it's ugly, but hopefully it might save someone's arse if they are desperate.

slinkhi
  • 947
  • 4
  • 16
  • 32
  • Good idea. Just two tweaks: 1. Reduce the timeout to 0. You [don't need 200ms](http://ejohn.org/blog/how-javascript-timers-work/) and you risk missing double-clicks. 2. Don't save the href to `someFunction.href`, just use a variable in a shared scope. – user123444555621 Apr 19 '12 at 04:36
0

Here ya go. Try this. Adjust accordingly for your needs (I removed the pdf link because one didn't exist in my fiddle).

EDIT: Tested in FF and Chrome. Let me know if it works for ya.

http://jsfiddle.net/lazerblade01/dTVz5/22/

Lazerblade
  • 1,119
  • 7
  • 17
  • Hello Lazerblade: I went to your link (using the latest version of FF) and console log gives me an error message "event is not defined" – slinkhi Apr 17 '12 at 00:01
  • Yeah, I tested in Chrome. I'll see if I can get to work in FF also, give me a few minutes. Need to adjust. – Lazerblade Apr 17 '12 at 00:12
  • AFAIK, `window.event` is not cross-browser compatible. I'm surprised it works in anything other than IE, and I seriously doubt you'll be able to ever use `window.event` in Firefox. – Matt Ball Apr 17 '12 at 00:29
  • No need to. Think outside the box. If you can't capture the event inside the first section of code because you can't change it, then what do you do? – Lazerblade Apr 17 '12 at 00:30
  • The hoops that code jumps through to achieve FF compatibility are completely unnecessary, and you _still_ changed the jQuery event binding code. At that rate, you might as well use one of the (much cleaner) options that I presented. – Matt Ball Apr 17 '12 at 00:32
  • IE requires far more hoops to accomplish things in CSS and js than FF does. But I digress. Yes, my solution is bulky and requires far more code than it should. You'd almost be better off doing a replace on all links containing pdf in the href and having them onclick to a different function. But whatever works... – Lazerblade Apr 17 '12 at 00:39
  • "Whatever works?" **[This works.](http://stackoverflow.com/a/10183118/139010)** The only reason that [this mess](http://jsfiddle.net/lazerblade01/dTVz5/22/) works is because you've bound a second event handler, but seriously, there is absolutely no need to write such a train wreck of code. [This binds a second handler as well](http://jsfiddle.net/mattball/pNqzD/), and is far more clear, concise, and maintainable. I'm sorry, but http://xkcd.com/386/ – Matt Ball Apr 17 '12 at 00:48
  • Ouch. Except you didn't meet the OP's request to NOT modify the document.ready. – Lazerblade Apr 17 '12 at 00:55
  • I changed it exactly as much as you did - only the selector. – Matt Ball Apr 17 '12 at 00:59
  • yeah..so if I am able to change the jQuery code or onclick call...i can pass an object reference easy enough. The problem is that I have a client that is willing to let me change this function within a javascript file, but is unwilling at this time to change the jQuery selector or onclick call that is on-page :( – slinkhi Apr 17 '12 at 01:19