using jquery 'this' to condense code - javascript

I try not to ask questions, but I can't figure out what should be very easy. I'm building a site for practice briannabaldwinphotography.com. I'm just trying to condense this so that I could just click on an anchor and it smooth scrolls to a <section> with an id the same name as the anchor. Ex: the 'about' li anchor has an href of #section_three and will scroll to the <section> with an id of section_three. I tried like 10 different variations and it won't work for me. Sort of what I'm looking for would be $(this).attr("href").offest().top}....etc. Here is the code I want to condense. Thanks.
$(function() {
$("[href='#section_three']").on("click", function() {
$("html body").animate({"scrollTop":$("#section_three").offset().top}, 1000);
return false;
});
$("[href='#section_two']").on("click", function() {
$("html body").animate({"scrollTop":$("#section_two").offset().top}, 1000);
return false;
});
$("[href='#section_four']").on("click", function() {
$("html body").animate({"scrollTop":$("#section_four").offset().top}, 1000);
return false;
});
$("[href='#section_one']").on("click", function() {
$("html body").animate({"scrollTop":$("#section_one").offset().top}, 1000);
return false;
});
});

If you use the attribute starts with selector (^=) you can get all elements with an href beginning with "#section_", bind a handler to those, then within the handler use this.href to get the href of the particular element that was clicked:
$(function() {
$("[href^='#section_']").on("click", function() {
$("html body").animate({"scrollTop" : $(this.href).offset().top}, 1000);
return false;
});
});
Note that this.href does the same job as $(this).attr("href"), but more efficiently: no need to create a jQuery object to access a property of the element that you can get to directly.

Since the href in each case matches the target element it makes it fairly simple
$("[href^='#section']").on("click", function() {
var targetSelector = $(this).attr('href');
$("html body").animate({"scrollTop":$(targetSelector).offset().top}, 1000);
return false;
});
If those elements have a common class or better path through parent class and tags you could improve the initial selector performance

Related

jQuery not executing code for new element with new id

I have an image, and when I click on it I want it to change to a different image and change its ID as well. Then when I click on this new image, it reverts back.
$(document).ready(function(){
$("#name_edit").click(function(){
$(this).attr("src", "img/tick.png");
$(this).attr("id","name_confirm");
});
$("#name_confirm").click(function(){
$(this).attr("src", "img/edit.png");
$(this).attr("id","name_edit");
});
});
I have successfully done the first step, going from #name_edit to #name_confirm. However, not the reverse.
How do I go about solving this?
My suspicion is that since I'm using (document).ready, jQuery is preparing itself for elements already on the page. However, the element with the ID name_confirm does not exist until the image is clicked on.
Thanks.
The element that you are working on is always the same...
$(document).ready(function(){
// use just the first id value to find it in the DOM
$("#name_edit").click(function(){
var item = $(this);
var id = item.attr('id');
if(id === 'name_edit') {
return item
.attr("src", "img/tick.png")
.attr("id","name_confirm")
;
}
return item
.attr("src", "img/edit.png")
.attr("id","name_edit")
;
})
;
});
I think you have chosen bad solution for your problem.
1) Why your code doesn't work:
You bind 2 events only 1 time, whne your document loaded. So, jquery finds #name_edit element and bind onclick event on it. But jquery cannot find #name_confirm element, because it doesn't exists on document ready)
In your code you should bind 1 onclick event, but have some attr (for example class for checking your state).
Something like:
<img id="main_image" class="name_edit"/>
<script>
var img_paths = ["img/tick.png", "img/edit.png"]
var img_index = 0;
$("#main_image").click(function(){
if($(this).attr("class") == "name_edit"){
$(this).attr("src", "img/tick.png");
$(this).attr("class","name_confirm");
}
else{
$(this).attr("src", "img/edit.png");
$(this).attr("class","name_edit");
}
});
</script>
Other solutions: You can create 2 images and show/hide them.
Or use styles with background attr. With pseudoclasses or classes.
Also you can store image pathes in array and tick array index on click.
Something like:
var img_paths = ["/content/img1.png", "/content/img2.png"]
var img_index = 0;
$("#main_image").click(function(){
$(this).src = img_paths[img_index];
img_index = !img_index;
})
It is not working because you are referencing the same elements, try this:
(function(window, document, $, undefined){
$("#name_edit").on("click", function(){
var self = $(this);
if(self.attr("id") === "name_edit") {
self.attr("src", "img/tick.png");
self.attr("id", "name_confirm");
} else {
self.attr("src", "img/edit.png");
self.attr("id", "name_edit");
}
});
})(this, this.document, jQuery);
Also for easier to understand code you could use classes like this:
(function(window, document, $, undefined){
$(".name_edit").on("click", function(){
var self = $(this);
if(self.hasClass("name_edit")) {
self.attr("src", "img/tick.png");
self.removeClass("name_edit").addClass("name_confirm");
} else {
self.attr("src", "img/edit.png");
self.removeClass("name_confirm").addClass("name_edit");
}
});
})(this, this.document, jQuery);
To simplify replacing classes you could even add your own $.fn.replaceClass(); like this:
jQuery.fn.replaceClass = function(classA, classB) {
this.removeClass(classA).addClass(classB);
return this;
};
Then use it like this:
(function(window, document, $, undefined){
$(".name_edit").on("click", function(){
var self = $(this);
if(self.hasClass("name_edit")) {
self.attr("src", "img/tick.png");
self.replaceClass("name_edit", "name_confirm");
} else {
self.attr("src", "img/edit.png");
self.replaceClass("name_confirm", "name_edit");
}
});
})(this, this.document, jQuery);
I can confirm what the others said.. the jquery gets run on document ready, but doesn't get updated subsequently - so it basically gets the correct element from the dom, and assigns the click event. It has no event for the name_confirm.
so this code does nothing...
$("#name_confirm").click(function(){
$(this).attr("src", "img/edit.png");
$(this).attr("id","name_edit");
});
See it not work in this instructive jsfiddle
Of course does the id need to change? is it possible to use for example a specific class for the img? then you could make the second click bind on the class instead... for example see this working example, which still changes the src and id...
Try On method:
$(document).on('click', '#name_edit', function(){
$(this).attr("src", "img/tick.png");
$(this).attr("id","name_confirm");
});
$(document).on('click', '#name_confirm', function(){
$(this).attr("src", "img/edit.png");
$(this).attr("id","name_edit");
});

Javascript , jQuery - what have I done wrong?

$(document).ready(function () {
$("href").attr('href', 'title');
});
$('a[href$=.jpg]').each(function () {
var imageSrc = $(this).attr('href');
var img = $('<img />').attr('src', imageSrc).css('max-width', '300px').css('max-height', '200px').css('marginBottom', '10px').css('marginTop', '10px').attr('rel', 'lightbox');
$(this).replaceWith(img);
});
});
This is the jQuery code I have at the moment, which I want to change all links' href to the same as their title, before then embedding them in the page. Yet with the changing href to title bit in the code, it stops working. I'm new to Javascript so am definitely doing something wrong, just not sure what yet! Any help much appreciated!
Thank you guys
EDIT
This is the html that I want to change:
<p class="entry-content">Some interesting contenthttp://example.com/index.php/attachment/11</p>
You are changing it wrong, you are trying to select href elements instead of a.
This fix should do it:
$("a[title]").each(function() {
$(this).attr('href',$(this).attr('title'));
});
It will select all a elements with title and set the href with this value.
Here's a much more efficient way.
Since you're just replacing the <a> elements, there's really no need to change its href. Just select the <a> elements that end with jpg/jpeg, and use that attribute directly.
Example: http://jsfiddle.net/5ZBVf/4/
$(document).ready(function() {
$("a[title$=.jpg],[title$=.jpeg]").replaceWith(function() {
return $('<img />', {src:this.title, rel:'lightbox'})
.css({maxWidth: 300,maxHeight: 200,marginBottom: 10,marginTop: 10});
});
});​
Your .each() is outside the .ready() function.
You can accomplish the href change easily like this:
$(document).ready(function () {
$("a").attr('href', function() { return this.title; });
});
The .attr() method will accept a function where the return value is the new value of (in this case) href.
So the whole thing could look like this:
Example: http://jsfiddle.net/5ZBVf/3/
$(document).ready(function() {
$("a[title]").attr('href', function() { return this.title; })
.filter('[href$=.jpg],[href$=.jpeg]')
.replaceWith(function() {
return $('<img />', {src:this.href, rel:'lightbox'})
.css({maxWidth: 300,maxHeight: 200,marginBottom: 10,marginTop: 10});
});
});
This line:
$("href").attr('href','title');
Is finding all href elements and replacing their href attr with the string 'title'. Since there is no such thing as an href element, Try this instead:
// for every anchor element on the page, replace it's href attribute with it's title attribute
$('a').each(function() {
$(this).attr('href', $(this).attr('title');
});
Check this out: http://jsfiddle.net/TbMzD/ Seems to do what you want.
Note: $(document).ready() is commented because of jsfiddle, you actually need it in your code.
Try:
$("a").each(function () {
var $this = $(this);
$this.attr('href', $this.attr('title'));
});

jQuery: hijack a link and find its parent

I know how to hijack a link in jQuery, and I know how to find an element's parent, but I can't seem to combine the two. I have multiple divs, each of which contains a link. I want to hijack the link and update the parent div's content.
<div class="container-1">
Add content
</div>
<div class="container-2">
Add content
</div>
Here's what I have with jQuery:
$(function() {
$(".pager A").live("click",
function() {
$.get($(this).attr("href"),
function(response) {
$(this).parent().attr("id").replaceWith(response); // This is wrong
});
return false;
});
});
The line with the "This is wrong" comment doesn't have what I want for $(this). It appears to contain the result from the previous expression, not the element I selected (".pager A").
How can I do this?
Bonus question: Visual Studio complains that ".get is a reserved word and should not be used as an identifier". What exactly is the problem?
EDIT: Sorry, I meant <div id="container-1">, not <div class="container-1">. Ditto for the 2nd div.
Try saving the reference to the current execution context where it points to the anchor to refer to later in the callback:
$(function() {
$(".pager A").live("click",
function() {
var el = this;
$.get($(el).attr("href"),
function(response) {
$(el).parent().html( response ); // is this what you want? .attr('id') would return a string and you can't call jQuery methods on a string.
});
return false;
});
});
First of all:
$(function() {
$(".pager A").live("click",
function() {
var $link = $(this);
$.get($(this).attr("href"),
function(response) {
$link.parent().attr("id").replaceWith(response); // This is wrong
});
return false;
});
});
You shouldn't use $(this) in callback function.
And the second - your link's parent element doesn't have id attribute. If you want to replace it's content use something like html() or text()

Update dynamic html attribute

What im trying to do is when the p inherits the class "active" that div.test will print the link rel correctly.
Currently if the page loads without the class assigned to the p tag, it will not. How can I make it happen when the p tag inherits the class "active" the link printed in div.test will get the rel printed correctly?
$(document).ready(function(){
var relvar = $('p.active').attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
$("p").click(function () {
$(this).toggleClass("active");
});
});
I am not sure what you asking. Are you saying that you would like this code:
var relvar = $('p.active').attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
To be run whenever the <p> element changes classes? If so, there is no "onchangeclass" event or anything like that, but you could actually create your own event to handle this:
$('p').bind('toggleActive', function() {
if($(this).hasClass('active')) {
var relvar = $(this).attr('rel');
$("div.test").html("<a rel='"+ relvar +"'>hello</a>");
}
}).click(function() {
$(this).toggleClass('active').trigger('toggleActive');
});
Check this code in action.
This is actually kind of roundabout - it would be simplest to just do the logic in the click handler itself. The main advantage of moving it to its own event is that if you then need to do this elsewhere in the code you can keep that logic separate and just "trigger" it as you need.
Not quite sure if this is what you are going for, but can you not handle it in the click code?
$(document).ready(function() {
$('p').click(function() {
$(this).toggleClass('active');
if ($(this).hasClass('active')) {
relvar = $(this).attr('rel');
$('div.test').html("<a rel='" + relvar + "'>hello</a>");
} else {
$('div.test').html("<a>hello</a>");
}
});
});
As far as I know, you will have to bind to some event in order for it to check and see if it needs to update the div.

How can I make this repetitious jQuery less so?

I have 4 blocks of jQuery that look like this:
$('#aSplashBtn1').click(function(){
$('#divSliderContent div').hide();
$('#divSplash1').fadeIn('slow');
return false;
});
$('#aSplashBtn2').click(function(){
$('#divSliderContent div').hide();
$('#divSplash2').fadeIn('slow');
return false;
});
$('#aSplashBtn3').click(function(){
$('#divSliderContent div').hide();
$('#divSplash3').fadeIn('slow');
return false;
});
$('#aSplashBtn4').click(function(){
$('#divSliderContent div').hide();
$('#divSplash4').fadeIn('slow');
return false;
});
I've tried learning more about javascript arrays and for loops but when I try to implement it into this code it only ends up working for the number 1 block. Could someone show me how they would accomplish optimizing this?
A variation on Sosh's answer
$('#aSplashBtn1').click(hideAndFadeIn('#divSplash1'));
$('#aSplashBtn2').click(hideAndFadeIn('#divSplash2'));
$('#aSplashBtn3').click(hideAndFadeIn('#divSplash3'));
function hideAndFadeIn(splash){
return function() {
$('#divSliderContent div').hide();
$(splash).fadeIn('slow');
return false;
};
}
If the clickable items are siblings, you can do:
$('#aSplashBtn1').siblings().andSelf().click(function(e){
$('#divSliderContent div').hide();
$('#divSplash'+e.target.id.substr(e.target.id.length-1)).fadeIn('slow');
e.preventDefault();
});
var $divSlider = $("#divSliderContent div");
$('*[id^=aSplashBtn]').live('click', function(e){
// Get the number from the id of the clicked element
var id = this.id.match(/^aSplashBtn(\d+)$/)[1];
$divSlider.hide();
$("#divSplash" + id).fadeIn('slow');
// Preferred as opposed to return false
e.preventDefault();
});
This will set a single handler that will match every element with an id that starts with aSplashBtn. Your id's could go as high as you wanted (i.e. #aSpashBtn100) and it would still pair with the correct div#divSplash100.
Also, I cached #divSliderContent div in its own variable since you don't want jQuery to 'look it up' again on each click.

Categories