I try to have access to the row i clicked to add or remove a class, but it seems like i misinterpreted the value of this. Isn't it supose to be the DOM where the event go called (in this case, the <li>)? Here is my code:
JAVASCRIPT
$(document).on('click', '.ToDownload', function()
{
if($(this).className.lastIndexOf("isSelected") != -1)
{
$(this).addClass("isSelected");
$(this).css('border', '2px solid #000099')
}
else
{
$(this).removeClass("isSelected");
$(this).css('border', 'none')
}
});
HTML
<li id="addedDownloadFileRow" class="fitting ToDownload">
<a href="#">
<div class="ui-grid-a">
<div class="ui-block-a">test1</div>
<div class="ui-block-b">test2</div>
</div>
</a>
</li>
In fact, i thought i could use the property className to find if my row is already selected, but it seems like this isnt the DOM of the <li> tag. Any information or a way to see what this really is would be appreciated.
P.S. The class "fitting" is only used for some css purpose.
this is a DOM Element, $(this) is a jQuery object
Full working code is in http://jsfiddle.net/tomi77/xgv8q9md/
If you use Chrome (not sure whether this works in Firefox), you can log the value of this to the console.
If it is a jQuery object, it might not be clear to see which element it refers to, however it's straightforward to get the underlying element out.
console.log(this[0]);
This will give you a minimal representation of the element itself and if you hover over it, you'll see the element highlighted in the web view itself.
This lets you see exactly which element it refers to. As mentioned in the comments, you can also log the direct object form of the element to the console with console.dir(element).
Related
On a web page we have a list of profiles. On the right hand side of the profile is some text, followed by an arrow img#arrow.
When img#arrow is clicked, we have the following jQuery we hope to run:
However, the corresponding .bottom-sec is not toggling.
jQuery('#arrow').click(function(){
var $parent = $(this).parent();
$($parent).addClass('active');
jQuery($parent +' .bottom-sec').toggle();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="profile-right">
<h2>Bob Brown</h2>
<h3>Non-Executive Chairman</h3>
<p>Intially showing text.</p>
<div class="bottom-sec" style="display: none;">
<p>Initially hidden text.</p>
</div>
<img id="arrow" src="/wp-content/themes/wtc/images/icons/down-arrow-circle-hi.png">
</div>
Problem
The problem with your code is exactly what the comment on your question is saying, but he didn't explain anything:
You're combining two different ways of selecting elements. One is with selectors, the other is traversing. You're using them in a way which isn't possible (the $parent + ' .bottom-sec' part). The comment linked to a jQuery page about traversing which you should definitely read! It tells you a lot about how to use traversing functions, which you could use!
Solution
There are multiple solutions to this, but I'll write down the one I think is the best:
First of all, change the HTML a bit. I've removed the element style of .bottom-sec and changed the id of the image to a class, because you have multiple images with the same id on the page, which is not a recommended thing to do. Classes can occur more than once, id's cannot.
<div class="profile-right">
<h2>Bob Brown</h2>
<h3>Non-Executive Chairman</h3>
<p>Intially showing text.</p>
<div class="bottom-sec">
<p>Initially hidden text.</p>
</div>
<img class="arrow" src="/wp-content/themes/wtc/images/icons/down-arrow-circle-hi.png">
</div>
I've reduced the JavaScript to the following. Note that is just reduced to one line, where a click on the .arrow element goes searching for the closest .profile-right parent. If, for whatever reason, you decide to change the HTML and the .arrow element is no longer a child of the .profile-right, this code still works. The only thing it does is toggle an active class on the .profile-right.
jQuery(document).on('ready', function() {
jQuery('.arrow').on('click', function(){
jQuery(this).closest('.profile-right').toggleClass('active');
});
});
The document ready listener was added because of OP's comment.
With CSS, we can use the new .active class to show or hide the element.
.profile-right .bottom-sec {
display: none
}
.profile-right.active .bottom-sec {
display: block
}
Original Code Fix
If for some reason you wanted to use your original code, this is how it should be:
// Nothing wrong about this part.
// Your only worry should be that there could be
// multiple elements with the same ID, which is something really bad.
jQuery('#arrow').click(function(){
// This part is correct, no worries
var $parent = $(this).parent();
// Removed the $(...), because $parent is already a jQuery object
$parent.addClass('active');
// Changed the selector to a find function
$parent.find('.bottom-sec').toggle();
});
You could also combine all of the code inside the listener function to just one line:
jQuery('#arrow').click(function(){
$(this).parent().addClass('active').find('.bottom-sec').toggle();
});
Change your js code like below.
jQuery('#arrow').click(function(){
var $parent = $(this).parent();
$($parent).addClass('active');
jQuery($parent).find('.bottom-sec').toggle();
});
In your event listener you can catch the element (the down arrow) that triggered the event. It will be referred as this.
Then you can go through the DOM tree using .next() and .parent() to access the <div> to toggle.
Note: you may need more functions than the one I explained above.
Note 2: without code or more detailed information, we can't help you further, I will edit this answer if you add details.
When adding a dynamically added element, how can I get attributes for that element (when clicking on it, for example)? I figured out that I need to delegate an event, but I still can't access any of the attributes of that event.
This JSFiddle shows the issue problem: https://jsfiddle.net/wgc499n9/
$(this).data('index') comes up as 'undefined' - I think $(this) is referencing 'document' instead of .remove_link; even the event data doesn't seem to have any useful information in it. $(this).attr('id') also comes up as 'undefined'.
In the end, I just need to be able to click that remove link to remove the row it's on. How can I accomplish that? I even tried inline JS, but that caused even stranger behavior.
P.S. I also learned that my dynamically added data-index attribute is not stored in the DOM; jQuery stores it separately, so its containing element has to be accessed by using .find()...but I can't figure out how to use .find() to access the specific individual elements I need.
Use element event(e) parameter instead this:
let i = 0;
$('#add').on('click', () => {
$('#container').append(`<div>row #${(i+1)} <a "href="#" data-index="${i}" class="remove_link">remove</a></div>`);
i++;
})
$(document).on('click', '.remove_link', (e) => {
//alert(JSON.stringify(e));
alert($(e.target).data('index'));
})
.remove_link {
color: red;
font-size: 0.8em;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="add">Add row</button>
<div id="container"></div>
For more detail read difference b/w $(this) ans event.target.
In your event handler, this represent window. You have access to e.target to get the clicked element.
This should works:
$('#container').on('click', '.remove_link', (e) => {
alert($(e.target).data('index'));
})
I am very new to Javascript/JQuery and I am going through the code of a colleague of mine. He has created the very common "FAQ" list on a website where the answer is not immediately displayed, only the question until the user clicks the arrow, it then shows the answer.
I am trying to figure out how he got this to work. I understand all the HTML and the CSS (it looks fine), but I can't seem to understand how to get the Jquery to work or where to call the code when the user press the arrow on the question to display the answer.
The code he seemed to use is at the bottom. Once again, all the HTML and CSS is linked up so I think it is a matter of simply how to use the code.
If anyone can offer any help, that would be appreciated.
Thanks!
$("#faq").on("click", "div > a", function() {
return $(this).next().toggle().closest("li").toggleClass("arrow_up"), !1
})
Let me annotate his code for you. It uses some shorthand that can be a little confusing for beginners.
// Select the element with an id attribute of "faq".
// When an <a> which is a first-level child of a div inside of
// #faq is clicked, perform the following actions
$("#faq").on("click", "div > a", function() {
// "this" references the <a> tag.
// $(this) wraps it in a jQuery wrapper
return $(this)
// get the next sibling of the <a>. It is our <p>
.next()
// switches the element.style.display between none and block
.toggle()
// get the nearest parent <li> element.
.closest("li")
// add or remove the arrow_up CSS class
.toggleClass("arrow_up"), !1 // !1 is a shortcut for false
});
I have a full distilled and annotated reproduction in this jsFiddle link
He also uses a shorthand for return false as well. Notice that the body of his event handler is all on one line. He could have split it into two lines, but he used the comma operator to make it fit on just one.
$(this).next().toggle().closest("li").toggleClass("arrow_up");
return false; // false === !1;
Returning false from a jQuery event handler prevents the event from reaching parent elements in the DOM.
That means:
//Bind a click function on every a tag in #faq
$("#faq").on("click", "div > a", function() {
// Toggle Class (so if the closest <li> Element has class "arrow_up" then remove it, otherwise add it)
return $(this).next().toggle().closest("li").toggleClass("arrow_up"), !1
Check out here for Example "Bootstrap Collapse" which is exactly the same you are looking for:
http://getbootstrap.com/javascript/#collapse
There is also a Demo Code provided and you see how to handle that.
I have a small problem with a jQuery script I wrote.
I have an HTML structure like this:
<div id="navigation">
<ul>
<li><b>Text1</b></li>
<li><b>Text2</b></li>
...
</ul>
</div>
Then, I have a click function binded to those li/a tabs that sets the value of the current page to href:
var currentpage = $(this).attr('href');
And, finally, an update function that is fired when it's needed that do many thing, but also changes the style of the currently selected li/a tab:
$('#navigation a').each(function()
{
var tab = $(this);
tab.parent().toggleClass('current', (tab.attr('href') == currentpage));
});
Everything works fine, but today I was trying to rewrite the last function on one line only -without calling each()- and I can't get it to work.
I've tried many solutions like:
$('#navigation a').parent().toggleClass('current', ($(this).children(':first').attr('href') === currentpage));
$('#navigation a').parent().toggleClass('current', ($(':only-child', $(this)).attr('href') == currentpage));
Can someone help me out?
Thanks!
You can't rewrite it as you'd like to.
The original code has to use ".each()" because it needs access to each individual <a> element in order to do its thing. In your rewrite, you're imagining that you can get this set to each element being processed, but that's just not how this works in JavaScript. In your attempted rewrite, the value of this in those parameters to "toggleClass()" will be this as it stands outside that entire jQuery function call chain. It'll have absolutely nothing to do with the <a> elements being processed by the call to "toggleClass()".
when your function is triggers i.e. on clicking the in that function you can get the reference to the clicked element, tag by using $(this). Then your code should be
$(this).parent().toggleClass('current', ($(this).children(':first').attr('href') === currentpage));
I am not very sure with the use of "this" [current context] in jquery.What I know is- it prevents the dom from searching all the elements, it just work on that current element, which improve performance[correct me if I am wrong].Also I am not sure when to use this and when not.
lets say, should I go for
$("span",this).slice(5).css("display", "none")
or
$("span").slice(5).css("display", "none")
both will work, but I am not very clear as how really it works.can somebody explain it with a diff/proper example, and when to use what?
[EDIT]
$(function() {
$("#clickme").click(function() {
$("span",this).slice(5).css('display', 'block');//doesn't work ? why?
$("span").slice(5).css('display', 'block');//works..why?
});
});
enter code here <span id="clickme">Click me</span>
<span>itam1</sapn>
<span>itam2</sapn>
<span>itam3</sapn>
<span>itam4</sapn>
<span>itam5</sapn>
...upto10
Usually you can use the this keyword on event handlers since it will be a reference to the element that triggered the event and other jQuery functions like $.each.
For example when handling a click event lets say:
$('.parentElement').click(function () {
$('.foo', this).hide();
});
The above code, will hide all the elements with class foo that are descendants of the currently parentElement that was clicked.
The use of the context argument of the jQuery function is the equivalent of making a call to the find method:
$(expr, context);
// is just equivalent to:
$(content).find(expr);
EDIT: Looking at your example:
$("#clickme").click(function() {
$("span",this);//... (1)
$("span");//.. (2)
});
The first line, will look for all the span elements that are inside of #clickme (its descendants), since that element was the one that triggered the click event.
The second line, will look for all the span elements on the whole page.
How it works
Lets use this HTML for the examples:
<div id="container">
<div class="column">Link 1</div>
<div class="column">Link 2</div>
</div>
<div id="footer">
Link 3Link 3
</div>
The scoping parameter of the jQuery function should only be used if you already have a cached reference to a DOM element or jQuery wrapped element set:
var $set = $('#container');
$('a', $set).hide(); // Hides all 'a' tag descendants of #container
Or in an event:
$("#container").click(function(e){
$('a', this).hide(); // Same as call above
}
But it makes no sense to use it like this:
$('a', '#container').hide()
When it should be written like this:
$('#container a').hide();
Having said all that, it is generally cleaner and clearer to just use .find() instead of using the second parameter in the jQuery function if you already have the jQuery or DOM element. The first example I gave would be written this way instead:
var $set = $('#container');
$set.find('a').hide(); // Hides all 'a' tag descendants of #container
If this one call was the only reason you grabbed the #container object, you could also write it this way since it will still scope the search to the #container element:
$("#container a").hide(); // This is the same as $('a', "#container");
Why would you scope your selections
When jQuery looks for an unscoped selector, it will search through the entire document. Depending on the complexity of the selector, this could require a lot of searching. If you know that the element you are looking for only occurs within a specific parent, it will really speed up your code to scope the selection to that parent.
Regardless of what method of scoping you choose, you should always scope your selectors whenever possible.