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');
}
Related
I have the following code with a link that should delete the region it belongs to :
<a href="javascript:function() { $(this).closest(".DatesSelection").remove(); };">
<div class="CloseButton">
Close
</div>
</a>
The button is generated but when I click it, I have the error:
Uncaught SyntaxError: Unexpected token (
Can anyone help please ?
Cheers,
The issue is due to the function definition within the href attribute and the use of quotes. To fix this, remove the function() around your logic, use onclick for an inline handler and use separate quotes to delimit the atttribute value and the selector string:
<a href="#" onclick="$(this).closest('.DatesSelection').remove();">
However, a much better approach entirely would be use unobtrusive event handlers instead of stuffing inline JS code in to href (where it should never be) or on* event attributes (which are now massively outdated), like this:
$(function() {
$('.DatesSelection a').click(function(e) {
e.preventDefault();
$(this).closest(".DatesSelection").remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="DatesSelection">
<a href="#">
<div class="CloseButton">
Close
</div>
</a>
</div>
<div class="DatesSelection">
<a href="#">
<div class="CloseButton">
Close
</div>
</a>
</div>
<div class="DatesSelection">
<a href="#">
<div class="CloseButton">
Close
</div>
</a>
</div>
Another option is to use event delegation, set click event listener on some parent container and check whether the source of the event is the corresponding anchor.
event.target.tagName === 'A' checks if the event was triggered by a element
event.target.parentNode.className === 'DatesSelection' checks whether the parent of the element which triggered the event has class DatesSelection
if both conditions are met then remove the parent element of the one that has triggered the event
document.body.addEventListener('click', event => {
if (event.target.tagName === 'A' && event.target.parentNode.className === 'DatesSelection') {
event.preventDefault();
event.target.parentNode.remove();
}
});
<div class="DatesSelection">
Close
</div>
<div class="DatesSelection">
Close
</div>
I have a reporting function answerCardInnerLinkReportingCall which gets invoked on click on <a> tag inside a specific div. I use event.preventDefault(); to override the default click behavior.
Currently I am redirecting the user to the target url in the reporting function after sending all the reporting parameters using window.open('http://stackoverflow.com/', '_blank'); method.
jQuery(document).on('click','#answerCard a', function(event) {
event.preventDefault();
answerCardInnerLinkReportingCall(this);
});
If I use onclick function in the tag I would have returned true and it would make href work without me redirecting the user manually but is it possible to do the same in click handler? I can't use onclick since I dont have control over the html data.
I wanted to check if there is a better way of implementing this?
Edit1: Adding sample HTML
<div class="answer" style="display: block;">
<div class="well">
<div id="answerCard" answercardid="check_phone_acard">
<h3 id="answerTitle">check your phone</h3>
<div><ol class="answerSteps"><li>Go to <a title="Link opens in a new window" href="https://test.com" target="_blank">Check phone</a>. If prompted, log in.</li></ol></div>
<label id="seeMoreAnswer">Displaying 1 of 1 steps. </label></div>
<!-- Utility Section -->
<div class="util">
<span class="pull-left"><a id="viewFull" href="/test.jsp?sid=52345">View full article ?</a></span>
<span class="pull-right">
</div>
</div>
</div>
</div>
I guess you dont need to use any 'event.preventDefault();' if you want to use links native functionality after the script executed.
try like this
jQuery(document).on('click','#answerCard a', function(event) {
//event.preventDefault();
alert('script running');
answerCardInnerLinkReportingCall(this);
});
also created JS Fiddle. check it out.
You can use javascript's:
window.location.href = 'http://url.here.com';
To tell the browser to navigate to a page. Hope it helps.
Other way can be of returning true or false from answerCardInnerLinkReportingCall and depending on that call or dont call event.PreventDefault();
Try something like this:
$('#answerCard a').click(function(event) {
var loc = $(this).attr('href');
event.preventDefault();
answerCardInnerLinkReportingCall(loc, this);
});
function answerCardInnerLinkReportingCall(loc, that){
// your code to do stuff here
window.open(loc, '_blank');
}
See this demo fiddle
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.
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
I'm trying to use jQuery's click function to apply a hover state to a selected div, without differentiating the div's in the JavaScript. I'm currently using:
$(document).ready(function(){
$(".project").click(function() {
$("a.expand").removeClass("hovered");
$("a.expand").addClass("hovered");
$(".project_full").hide();
var selected_tab = $(this).find("a").attr("href");
$(selected_tab).fadeIn();
return false;
});
With the HTML:
<div class="project first project_gizmoscoop">
<div class="title">
GizmoScoop!
<div class="date">2012</div>
</div>
<a class="expand" title="(Caption)" href="#project_1">GizmoScoop!</a>
</div>
<div class="project project_sc">
<div class="title">
Striking Code
<div class="date">2011</div>
</div>
<a class="expand" title="(Caption)" href="#project_2">Striking Code</a>
</div>
The .hovered class is applied to the clicked link (specific styles from an external CSS file). However, everything is being chosen. (See http://www.codeisdna.com for an example).
I know what I'm doing wrong (I should be specifying the individual ID's or using HTML5 data attributes), but I'm stuck unnecessarily. I feel like a complete newb right now, that I can't do something this simple (although I've done more advanced stuff).
You simply need to take advantage of jQuery's flexibility (and good programming practice) and reduce your scope accordingly. You're already doing something similar with your variable definition. For example, to target only those a.expand elements inside the instance of .project that's clicked:
$(".project").click(function() {
$(this).find("a.expand").removeClass("hovered");
...
});
$(".expand").click(function() {
$(this).addClass("hovered");
..
});