Best way to find nearest href attribute? - javascript

Why I don't think it's a duplicate.
Hmm, I think that's slightly different to what I'm asking. I don't
want to add a listener to all A tags, rather, substract an href
attribute, if any, on a click event's target.
I'm trying to "Ajaxify" my whole site, so that when an user clicks ANY link contained within the page, a script sends the "url" or HREF attribute (of the clicked element) to an Ajax function, which in return, renders the requested content (as indicated by the link clicked).
I need to find the HREF attribute of the clicked element, if the element is a link. The problem here, is that many elements can be contained within an A tag (because of the way I've structured them), and e.target.href doesn't necessarily always return an HREF attribute.
Here is what I have so far:
function ajaxifyLinks(e) {
var target = e.target;
e.preventDefault();
while(!target.href) {
target = target.parentNode;
}
if(target.href) {
ajaxLoad(target.href);
}
}
document.body.addEventListener('click', ajaxifyLinks);
And here are examples of different "clickable" links that I have:
<!-- Link -->
<a href="/cats">
cats
</a>
<!-- Link -->
<a href="/hello">
<span>
<span> hi </span>
</span>
</a>
<!-- Link -->
<a href="/bye">
<span>
bye
</span>
</a>
As you can see, this is why e.target.href won't always return the HREF attribute, because you are actually clicking a "linked" span element, however, the browser does take you to the link. Why does this happen? And is there any way I can benefit from that behavior? (As in, extracting the location where the browser is taking you, even if you aren't clicking over an A tag).
I don't like my solution, because the while loop just keeps looking up the DOM tree, sometimes needlessly (when e.target isn't a link or contained by a link).
Thanks.

If the element clicked does not have an href, it searches it's parents for an element that has an href. Vanilla JS solution.
function findUpTag(el, attr) {
while (el.parentNode) {
el = el.parentNode;
if (el[attr]) {
return el;
}
}
return null;
}
document.body.onclick = function (event) {
event.preventDefault();
var href = event.target.href;
if (!href) {
var closest = findUpTag(event.target, 'href');
if (closest) {
href = closest.href;
}
}
document.getElementById('output').innerHTML = 'element clicked: ' + event.target.nodeName + '<br>closest href: ' + href;
};
a,
output {
display: block;
}
<!-- Link -->
<a href="/cats">
cats
</a>
<!-- Link -->
<a href="/hello">
<span>
<span> hi </span>
</span>
</a>
<!-- Link -->
<a href="/bye">
<span>
bye
</span>
</a>
<output id="output"></output>

Use the .parent(), ref: http://api.jquery.com/parent/
for example, you can do
var hrefElem = $(target).parent('*[href]');
var link = hrefElem.attr('href');

New answer:
<!-- Link -->
<a href="/cats">
cats
</a>
<!-- Link -->
<a href="/hello">
<span style="pointer-events: none;">
<span style="pointer-events: none;"> hi </span>
</span>
</a>
<!-- Link -->
<a href="/bye">
<span style="pointer-events: none;">
bye
</span>
</a>

Just attach a click handler to each link on the page:
function ajaxify(e)
{
e.preventDefault();
ajaxLoad(this.href);
}
[].forEach.call(document.getElementsByTagName('a'), function(el) {
el.addEventListener('click', ajaxify.bind(el));
});

Have a look at What is event bubbling and capturing? to understand how events propagate through the DOM.
The technique of capturing anchor links and loading them via Ajax is referred to as Hijax. Because you're replacing content on the page, you can't simply set up a single event to handle all links, and you probably don't want to keep re-binding every page load, so the approach you are using is good, and is known as event delegation.
The last article describes exactly your problem (right at the very end), and also describes a solution similar to yours, which is really the best way to do it in this scenario. However, you could look at using a microlibrary to simplify some of the event delegation; one example is gator.js.

Related

JavaScript: onclick function to change another elements onclick

Intended Functionality
I'm looking for something that operates like this:
User clicks on the img
handclick function gets called and 'enables' the parent anchor of the img
If clicked again, the anchor will redirect the user to a new page
My Issue:
The below does 'enable' the link, but it also acts as if the link was clicked at the same time.
Is there any way to fix this functionality?
HTML Code:
<a href="#Url.Action("Index/" + #card.ID)" onclick="return false;" class="link">
<img src="~/Resources/#card.Image" id="#card.ID" onclick="handClick(#((int)card.Value), #card.ID)" class="card" />
</a>
JavaScript Code
function handClick(cardValue, cardID) {
*... irrelevant code ...*
var playedCard = document.getElementById(cardID);
*... irrelevant code ...*
playedCard.parentElement.onclick = function () { return true };
}
Since I don't know what the irrelevant code is I'll stay only on the first click enable issue.
My approach includes the href attribute. without it the link doesn't work. So, what I did was change the attribute's name into something else and when clicked, replace it with the actual attribute, thus "activating" the link.
Notice that the cursor changes into a pointer after the first click.
document.querySelectorAll('a[hrefx]').forEach(function(el) {
el.addEventListener('click', function() {
// This condition enable re-using the listener for other purposes.
if (this.getAttribute('hrefx')) {
this.setAttribute('href', this.getAttribute('hrefx'));
this.removeAttribute('hrefx');
}
});
});
<a hrefx="#">
<img src="https://picsum.photos/200">
</a>
<a hrefx="#">
<img src="https://picsum.photos/200">
</a>

How to restrict href link to <oblique> tag

<a href="myList/doctor">
<div>
<span> The important Info
<a data-toggle="modal" data-target="#mapModal">
<a data-toggle="modal" data-target="#mapModal"
id="obliqueIcon"> <oblique
class="iconSize">i</oblique></a>
</a>
</span>
</div>
</a>
document.getElementById("obliqueIcon").onclick = function(e) {
return false; // or use e.stopPropagation() and e.preventDefault()
}
I have the above code.Here the div can be clickable but the 'i' button here should open up a model box (data-target="#mapModal") but it is not since the anchor tag contains the 'href'.
What I am trying to do is let this code should not be changed but when I click on the oblique it should open up a model box but not redirecting to the link.Is there any way to restrict it.Please suggest help.Thanks.
So there are a couple of issues with your HTML: first, there isn't an <oblique> tag (did you mean <i>?), and second, you can't nest an <a> tag within another <a>.
That said, though, the more general form of what you're asking for -- a node within a link tag that will not fire that link if clicked -- is possible; all you need to do is prevent the click event from bubbling up from that node to the anchor tag:
document.getElementById("foo").onclick = function(e) {
// open your modal here
return false; // or use e.stopPropagation() and e.preventDefault()
}
<a href="https://example.com">
This should link to the other page...
<span id="foo">but this should not</span>
</a>
Added to the answer in response to comments below: here's the same code snippet applied to your HTML:
document.getElementById("obliqueIcon").onclick = function(e) {
return false; // or use e.stopPropagation() and e.preventDefault()
}
<a href="myList/doctor">
<div>
<span> The important Info
<a data-toggle="modal" data-target="#mapModal">
<a data-toggle="modal" data-target="#mapModal"
id="obliqueIcon"> <oblique
class="iconSize">i</oblique></a>
</a>
</span>
</div>
</a>
I do not get the error message you're reporting ("Cannot set property 'onclick' of null") but at a guess it may be because you're continuing to use invalid HTML (the nested <a> tags) -- possibly that's making those nodes inaccessible in some browsers? (I'll stress that this is only a guess; I don't have a lot of experience working with invalid HTML other than by fixing it, so I don't have a solid understanding of how all browsers might handle it. I've tested Safari, Chrome and FF, all work correctly even with the invalid HTML, but if you're using a different browser perhaps that's the cause. If you see the error on my second snippet but not on my first snippet, that would confirm the guess. If you see no errors in either snippet, then you have something else going wrong in your code.)

Click event toggling all classes rather than correct block

I have some collapsed/collapsible blocks whereby the first block is open and second/third closed. They work the way I want in terms of opening and closing, but I can't get my head around how to alter the function so that the plus and minus icons change for the correct block. At the moment all change at the same time no matter which block I open or close.
How I can alter the function so that the toggled block updates the correct icon?
function toggleDiv(divId) {
$("#"+divId).toggle();
$('.product-toggle span.icon').toggleClass('icon-plus icon-minus')
}
HTML
<p><span class="icon icon-plus" aria-hidden="true"></span><span class="toggle-title">Features</span></p>
<div id="features">
Features
</div>
<p><span class="icon icon-plus" aria-hidden="true"></span><span class="toggle-title">Specifications</span></p>
<div id="specifications">
Spec
</div>
<p><span class="icon icon-plus" aria-hidden="true"></span><span class="toggle-title">FAQ</span></p>
<div id="faq">
FAQ
</div>
Let me start off by saying no... just no!
Add the target in your markup as a data attribute:
<div class="product-toggle" data-target="features">
<p>
<span class="icon icon-plus" aria-hidden="true"></span>
<span class="toggle-title">Features</span>
</p>
</div>
<div id="features">
Features
</div>
Attach a listener to the product-toggle class like so:
$(document).on('click', '.product-toggle', function() {
var target = this.dataset.target;
$('#'+target).toggle();
$(this).find('span.icon').toggleClass('icon-plus icon-minus');
});
JsFiddle
Note : Inline events are discouraged; you should use jQuery click handlers as you're already using jQuery.
For example (Demo):
$('a.product-toggle').click(function(e){
$(this).closest('p').next('div').toggle();
$(this).find('span.icon').toggleClass('icon-plus icon-minus')
})
If you need to use inline event calls,
You need to alter the second line to get the icon for current element
function toggleDiv(divId) {
$("#"+divId).toggle();
$("#"+divId).prev('p').find('.product-toggle span.icon').toggleClass('icon-plus icon-minus')
}
because,
$('.product-toggle span.icon')
selects all the <div>s
or pass this with the click event.
<p><a href="javascript:toggleDiv('features',this);"...
and
function toggleDiv(divId,currEl) {
$("#"+divId).toggle();
$(currEl).find('span.icon').toggleClass('icon-plus icon-minus')
}
Here is something I came up with which is a more handy solution and is not using javascript in href.
$('.product-toggle').on('click', function(evt){
// This will be set to the context of the current element
$("#"+this.name).toggle();
$(this).find('.icon').toggleClass('icon-plus icon-minus');
});
This requires that you give the a tags a name instead of calling the function directly. Here is a link to the fiddle: http://jsfiddle.net/ttpfzrgL/
Try this
function toggleDiv(divId) {
var idSelector = "#"+divId;
$(idSelector).toggle();
$('p').has('idSelector').closest('span.icon').toggleClass('icon-plus icon-minus');
}

How to change a word in a h2 when certain page is clicked on

I'm trying to change a certain word in the title of a page dynamically with javascript depending on which link in the nav is clicked on. So for instance, if the "Asia" link is clicked I want the h2 to display: "You are in Asia" or if the "Europe link is clicked I want the h2 to say: "You are in Europe."
The html for the nav bar:
<div id="zone-nav">
<a href="" id="surge-btn"</a>
<a href="" id="latin-btn"</a>
<a href="" id="africa-btn"</a>
<a href="" id="asia-btn"</a>
</div>
The html I have thus far for the title that needs to be changed: `
<h2 id="zoneName">You are in<span id="zoneName"></span></h2>`
I know I need to write a function to determine what link is pressed, but I am a little confused on how to approach this.
if you add some extra markup to your html, you can use a single jQuery event handler:
<div id="zone-nav">
<a class="zone-select" href="" id="surge-btn">Surge?</a>
<a class="zone-select" href="" id="latin-btn">Latin</a>
<a class="zone-select" href="" id="africa-btn">Africa</a>
<a class="zone-select" href="" id="asia-btn">Asia</a>
</div>
now the event handler:
$(document).ready(function() {
$(".zone-select").on("click", function() {
$("#zoneName").html($(this).html());
};
});
Firstly you need to deal with your duplicate id here:
<h2 id="zoneName">You are in<span id="zoneName"></span></h2>
Note we cannot have the same id otherwise we don't know how to get an element by it's id. So remove the uneeded one on the h2:
<h2>You are in <span id="zoneName"></span></h2>
Then add event's to your a tags:
<div id="zone-nav">
<a onclick="update('Surge')" id="surge-btn" >item1</a>
<a onclick="update('Latin')" id="latin-btn" >item2</a>
<a onclick="update('Africa')" id="africa-btn" >item3</a>
<a onclick="update('Asia')" id="asia-btn" >item4</a>
</div>
Note: This can be done purely in JavaScript or be done easily in jQuery. But since you did not mention it I will not be using jQuery. We could iterate through by ClassName and have the links be a class, but that's no more simple then the way above.
For the JavaScript we need to return false to prevent the default behavior of a anchor tag:
function update(text) {
document.getElementById("zoneName").innerHTML = text;
return false;
}
Here is a working Fiddle
Would there be a way to keep the updated text in the even if the page reloads?
Yes there is a way to do this without having to use a server-sided language. What I will do is use HTML 5 web storage, note this will only work for browsers that support HTML 5 (which is all of the modern ones), you can use cookies if you need support for older browsers that work similarly for the following example. In this case I will be using sessionStorage which saves the information even until the browser is closed.
I will emulate a href to the same page for the <a> tags, we need to do this because we need to save out information before we move to a new page. After I save I will call location.reload() that will act as a refresh. Note that you could make this move to an entirely new page as well, just include the script on the new page and use window.location.href = "newPageUrl" ( jsfiddle prevents me from moving to a new page ).
The HTML will be the same but the JavaScript will be updated as followed:
window.onload = function() { // When the page loads
if(sessionStorage.zoneName) { // Check if the session exist
// update the page with the session info
document.getElementById("zoneName").innerHTML = sessionStorage.zoneName;
}
}
function update(text) {
sessionStorage.zoneName = text; // store the text into a session called "zoneName"
location.reload(); // reload the page
return;
}
Here is a working Fiddle
Here's an example of what you could do for the africa-btn (this will require jQuery, I hope that's alright):
$(document).ready(function() {
$("#africa-btn").on("click", function() {
$("#zoneName").html("Africa");
};
// Other buttons here
});
What this is doing is attaching an action to the "click" event of the africa-btn anchor tag. When it's clicked it should update the span's html as described above. You can add further click events in a similar way.
Using $("#africa-btn") to bind the click event is a way to do it specifically for that one button, so you'll have to do it for each id.
This would update the selected zone in the dom
<div id="zone-nav">
<a id="africa-btn" onclick="updateZone('africa'); return false;"> </a>
<a id="asia-btn" onclick="updateZone('asia'); return false;"> </a>
</div>
function updateZone(countryName){
document.getElementById('zoneName').innerText = countryName;
return false;
}
are you looking for something like this :
Simple html and javascript only:
http://jsfiddle.net/q9L37c32/
Asia

html anchor tag reference

i have an anchor tag as below.
<a style="border:0px" href='javascript:deleteAttachment(this);' />
Inside the deleteAttachment, how can i get the anchor tag. Sending this to the method, sends the window element to the method.
function deleteAttachment(ancElement){
//Jquery operation on acnElement
}
Please helop me out.
I would recommend a slightly different approach, since what you're trying to do is a bit old.
assuming you already loaded jQuery, here we go:
<a id="myFirstLink" href="someHref" />
<a class="otherLinks" href="secondHref" />
<a class="otherLinks" href="thirdHref" />
<script>
$(function() {
$('#myFirstLink, .otherLinks').click( function(event) {
// stops the browser from following the link like it would normally would
event.preventDefault();
// do something with your href value for example
alert( $(this).attr('href') );
});
});
</script>
So basically what you can do is this: simply generate all your anchors like you would normally would and apply the same class name to each of them - in my example the class would be "otherLinks".
After that, all your links will be handled by that anonymous function.
Use the onclick handler:
<a onclick="deleteAttachment(this)">
or, the cleanest and most accepted method nowadays, have just the raw link in the HTML:
<a id="deleteAttachment">
and add the click event programmatically, in a separate script block, on DOM load:
document.getElementByID("deleteAttachment").onclick =
function() { ... you can use "this" here .... }
you must set its ID attribute
<a id="myAnchor" style="border:0px;" href="javascript:deleteAttachment('myAnchor');"/>
then use jquery to find it
function deleteAttachment(ID)
{
var MyAnchor = $('#'+ID);
}

Categories

Resources