jQuery Function Problem (Parent/Child) - javascript

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));

Related

Deleting <li> issue

I'm building a recipe saving application where I have a form that looks like this http://jsfiddle.net/LHPbh/.
As you can see, I have a set of form elements contained in an <li>. You can click Add Ingredient and have more li's added to the field.
My problem is:
The first li is the only one that deletes. If you click Add Ingredient, and then try and delete that one, nothing works?
Is there a way to not have the first li have a delete by it, but all subsequent li's have a delete link on the side? (Just because there should always be at least one ingredient?)
When you call clone(), it isn't duplicating the events. You need to call clone(true) in order for it to do this, as explained in the documentation.
You did not put an event listener on the cloned elements. Also, you should not give the "delete"-link its own id, as those need to be unique.
To make the first ingredient have no delete button, just don't include one in your markup but only dynamically create and append them to the cloned elements:
var deleteButton = $("<a class='float-left'>Delete</a>").click(deleteThis);
$('ul#listadd > li:first')
.clone()
.attr('name', 'ingredient' + newNum)
.append(deleteButton)
.appendTo('ul#listadd');
function deleteThis() {
var li = $(this).closest('li')
li.fadeOut('slow', function() { li.remove(); });
}
Demo at jsfiddle.net
http://jsfiddle.net/LHPbh/2/
$('.deleteThis').live("click", function () {
var li = $(this).closest('li')
li.fadeOut('slow', function() { li.remove(); });
});
It is answer to the 1. point. The problem was, that the eventhandler binding did not happen in newly created elements, because this code runs only on the load of the page. This can be solved by using .live(). And an other problem was, that id-s must be unique. So instead id, here you can use class .deleteThis.
http://jsfiddle.net/LHPbh/19/
This has added answer to the 2. point:
if ($("#listadd li").length == 1) {
return;
}
If the list only contains 1 li element the rest of the callback will not run.
You are adding items that are added to the DOM dynamically, thus jQuery can't access them :)
In this case you can use the following code:
$(document).on('click', '.selector', function(e) {
//code here
});
Secondly, you were loading a quite old version of jQuery.
Thirdly, you were trying to select an element with an ID that already existed, and ID's can only exist one time. I've changed it to a class in the updated example.
Lastly, you were defining the class of the link twice like this:
<a class='float-left' id="deletethis" href='#' class="deletethis">Delete</a>
That also gave a problem, so I changed it to correct markup like this:
<a class='float-left deletethis' href='#'>Delete</a>
Good luck :) I've updated your jsFiddle here:
http://jsfiddle.net/q4pf6/

jquery nth-child as an argument in a function.

I have four paragraph elements. I want to toggle the next even element after clicking on an odd element.
Here's the arrangement.
<p>First</p>
<p>Second</p>
<p>Third</p>
<p>Fourth</p>
So, if I click on First, I would like Second to be toggled; and if I click on third, I'd like the fourth element to be toggled. I hope it makes sense.
Here's what I have been able to come up with so far.
$("p:odd").click(function(){
$("p:even").toggle("slow");
});
Now, this piece of code toggles ALL the even elements. I just want to toggle n+1, whenever I click an odd paragraph. Does it make sense? Is there a way for that function to take an argument so that after clicking on an odd paragraph, the next (n+1) is toggled? I'm not really sure how to pass an argument or what would be the best way of doing it.
Thank you
Inside all of your Javascript and jQuery methods, the item that triggers the event is automatically passed to the function as this. However, because of the way that variable scope isn't enclosed in Javascript, this can change depending on what other functions are called inside. Best practice is to set this to another variable immediately.
So, you can adjust your method like this:
$("p:odd").click(function(){
var self = this;
// I'm doing .next('p') to make your code safer in case there's something between the <p> elements.
$(self).next('p').toggle('slow');
});
how about you try .next()? http://api.jquery.com/next/
$("p:odd").click(function(){
$(this).next().toggle('slow');
});
You can cache the objects and use eq method:
var $p = $('p'),
$odd = $p.filter(':odd'),
$even = $p.filter(':even');
$odd.click(function(){
$even.eq( $odd.index(this) ).toggle('slow');
});
http://jsfiddle.net/TLucC/ | http://jsfiddle.net/uNu9y/

Add class to parent LI where A = current document?

I'm trying to append a class to an LI automatically if the filename matches the href (e.g; if the anchor has the href attribute set to about.php and the filename of the current page is about.php then it would append the class.) however, along the way I've hit some complications and I've been getting myself confused with the syntax a little...
So far I have this...
var filename = location.pathname.substring(1)
$(document).ready(function(){
$('a').each(function() {
if (this.href === filename) {
$(this).parent('li').addClass('current_page_item');
}
});
});
My navigation is constructed as shown here and as you can see, it works and everything but only when the class is set manually... so I'm trying to get it to be automatic from the actual filename.
I hope this make some sense to someone, as I'm really confused on how to get this working now!
Thank-you to anyone who contributes, it's of great help and will help me understand the jquery syntax further, actually selecting something specific and writing a logical statement in jquery really confuses me as it's very different to PHP, which is what I'm used to.
My markup looks like this, since I didn't include it before and just assumed people would look at the source code to understand what I was meaning (though, I should have put it here)
<nav>
<div class="container">
<ul class="group" id="effects">
<li>News</li>
<li>About</li>
<li>Races</li>
<li>Tools</li>
<li>FAQ</li>
<li>Contact Us</li>
</ul>
</div>
</nav>
Thanks.
I think you can do it as simple as this:
$(function(){
$('a').filter(function() {
return (this.href == location.href);
}).parent('li').addClass('current_page_item');
});
​Filter the anchor tags by their href attribute. Seems to work on this JSFiddle. For some reason, you have to hit run for it to work.
I assume that li tag is parent of anchor tag than you can try this-
$(this).parent().addClass('current_page_item');
instead:
$(this).parent('li').addClass('current_page_item');
Based on what little information you've provided in your question, I'd suggest (though this is untested):
var file = document.location.href.split('/').pop();
$('li a').filter(function(){
return this.href.indexOf(file) !== -1;
}).parent().addClass('current_page_item');
This gets the contents of the current page's URL and splits it by the / character and then assigns the last element of the array to the variable file, for example:
'http://example.com/directory/page.html'
is converted into an array:
["http:", "", "example.com", "directory", "page.html"]
And the last element of that array is assigned to the variable, so file becomes equal to:
'page.html'
The jQuery iterates over every a element within an li element and then, if it finds the string page.html within the href attribute it returns that a element, and adds the class-name to its parent element.
You could, instead, use the full document.location.href, of course; which would give:
var page = document.location.href;
$('li a').filter(function(){
return this.href == page;
}).parent().addClass('current_page_item');
This works much the same way, but instead of looking to see if the filename can be found within the URL, it checks that the href of the element is exactly equal to the current document.location.href.
References:
JavaScript:
Array.pop().
String.indexOf().
String.split().
*jQuery:
filter().

jqTransform Update Select Options

I'm dynamically altering a select list's options. I am using the jqTransform plugin. It won't update itself automatically, which I didn't expect it would, but I can find a method for updating the display. I can't even find a method for removing it completely.
What I'd like is to find a method such as formelement.jqTransformUpdate() that will fix this. Any ideas?
I know it's an old question, but maybe it helps someone. I couldn't find the answer, so I looked into jqtransform.js code.
Just comment this line:
if($select.hasClass('jqTransformHidden')) {return;}
And then, after "onchange" event run:
$('#container select').jqTransSelect();
function selectRating(rating) {
$("#ratingModal .jqTransformSelectWrapper ul li a").each(function() {
if (parseInt($(this).attr("index")) == rating - 1) {
$(this).click();
}
});
}
A JS function I used in my own application to select specific option with the given rating.
I think you can modify it to meet your needs.
The idea is to use a.click event handler to select specific option in the transformed select list.
hi please try the following to selectively reapply styling to newly created or
select box returned from the ajax request
$('#container select').jqTransSelect();
regarding this:
That adds another drop-down to the page every time I call it now
When you comment this line:
if($select.hasClass('jqTransformHidden')) {return;}
add this just below:
if($select.hasClass('jqTransformHidden')) $select.parent().removeClass();
it's not a very elegant solution, but it worked in my case, the new select is still nested inside child and so on but it's working fine.
It could be better, try to add new method in jqtransform.js:
$.fn.jqTransSelectRefresh = function(){
return this.each(function(index){
var $select = $(this);
var i=$select.parent().find('div,ul').remove().css('zIndex');
$select.unwrap().removeClass('jqTransformHidden').jqTransSelect();
$select.parent().css('zIndex', i);
});
}
after that, just call it each time you need to refresh the dropdown:
$('#my_select').jqTransSelectRefresh();

this, current context-when should I use in jQuery?

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.

Categories

Resources