Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

How would I add a data attribute using jQuery to items that haven't been loaded yet?

So I am developing an e-commerce site and I have a large image displaying the product with poplet images underneath with different views. When a poplet is clicked, the href value is taken and it replaces the large images html (I have a #largeimage wrapper and I am changing the img inside upon a poplet being clicked). I have that functionality down.

Now the problem lies with adding a zoom effect jQuery plugin. To use the plugin, I have to add a data-magnify-src attribute to the image I want zoomed with a src path to the larger version of the image. I have successfully found a way to use jQuery to add the data attribute on the initial large image, but when I am switching between poplet images, I lose the plugin effect. I swear, I have been taking all of these courses and I still feel like such a newb when it comes to JS/jQuery. Please excuse the really crude JS when adding the attribute. Really didn't take the time to refine and condense yet. Was prioritizing how the bloody hell to add the attribute to the next poplet item clicked.

Anyways, here is my current code for changing the large image and for adding the data attribute to the large image.

//New Poplet Functionality
/*===================================================*/
function poplet(e){
    e.preventDefault();
    var imgURL = $(this).attr('href');

    $('#largeimage').html('<img src="' + imgURL + '">');
}

//MAGNIFY
/*=======================================*/

function zoomEffect(){
  var addedAttr = "data-magnify-src";
  var originalExtension = $('.productLarge #largeimage > img').attr('src').slice(0,-4);
  var combinedExtension = originalExtension + "-large.jpg";

  $('.productLarge #largeimage > img').attr(addedAttr, combinedExtension);
}

$(function(){

    //Poplets
    $('body').ready(zoomEffect());
    $('.productPopletsItem a').removeAttr('onclick rel');
    $('body').on('click','.productPopletsItem a',poplet);
});

3 Answers

Colin Bell
Colin Bell
29,679 Points

You're only calling magnify when the page is first loaded. Same with your zoomEffect() function.

You need to change the image - which you are doing correctly - then implement zoomEffect() on the current image inside of .productLarge. Then call magnify() again right after to instantiate the plugin on the current photo.

So instead of having this at the bottom of your html

<script>
$(document).ready(function() {
  $('#largeimage > img').magnify();
});
</script>

You should be able to condense all of what you're trying to do into one function, and run that function every time one of the poplets is clicked

function poplet(e){
  e.preventDefault();
  var imgURL = $(this).attr('href');
  var addedAttr = "data-magnify-src";
  var originalExtension = $('.productLarge #largeimage > img').attr('src').slice(0,-4);
  var combinedExtension = originalExtension + "-large.jpg";

  //Change the image
  $('#largeimage').html('<img src="' + imgURL + '">');
  //Add the data-magnify-src attr and its created value
  $('.productLarge #largeimage > img').attr(addedAttr, combinedExtension);
  //Add magnification. Moved from your html script tag
  $('#largeimage > img').magnify();
}

// Run entire poplet() function every time a link in .productPopletsItem is clicked 
$('body').on('click','.productPopletsItem a', poplet);

We are getting closer! This makes a lot more sense. When I use this though, the zoom effect isn;t called on the initial large image. And then, upon clicking the poplet, it is using the previous images src path. It's currently live with the changes.

It's also preventing my initial image swapping.

Colin Bell
Colin Bell
29,679 Points

My bad. You should still have the

$(document).ready(function() {
  $('#largeimage > img').magnify();
});

to set that first image. Let me take a look at the other things really quickly.

Colin Bell
Colin Bell
29,679 Points

Okay, let's try this:

var originalExtension = $('.productLarge #largeimage > img').attr('src').slice(0,-4);

img isn't a direct child of #largeimage anymore. It's always nested inside of the magnify so remove the >

leave this in to prevent the lightboxes from popping up: $('.productPopletsItem a').removeAttr('onclick rel');

function poplet(e){
  e.preventDefault();
  //added largeImage as a var since it's used a few times
  var largeImage = $('.productLarge #largeimage img');
  var imgURL = $(this).attr('href');
  var addedAttr = "data-magnify-src";
  var originalExtension = largeImage.attr('src').slice(0,-4);
  var combinedExtension = originalExtension + "-large.jpg";

  //Change the image
  $('#largeimage').html('<img src="' + imgURL + '">');
  //Add the data-magnify-src attr and its created value
  largeImage.attr(addedAttr, combinedExtension);
  //Add magnification. Copied from your html script tag
  largeImage.magnify();
}

// Prevent lightboxes
$('.productPopletsItem a').removeAttr('onclick rel');

// Magnify first image on page load
$('#largeimage img').magnify();

// Add magnify on each subsequent click. Hopefully.
$('body').on('click','.productPopletsItem a', poplet);

Try that and let me know of any problems.

Tried it, and it still isn't working. Gah, I feel like it is right there and for some reason I am missing it. I removed the

// Magnify first image on page load
$('#largeimage img').magnify();

as it was undefined at the bottom. Upon clicking on the poplet image, the new attribute isn't carrying over. Tried to log it and see what is going on but all I received in return was

[img#catlproduct_10195617, prevObject: m.fn.init[1], context: document, selector: "#largeimage img", jquery: "1.11.2"]

Your answer lead me down the correct path. All in all, I just added a class upon click and changed the .magnify() function to target that after a poplet was clicked. Thank you sir!

Colin Bell
Colin Bell
29,679 Points

Cool. Glad it helped!

Troubleshooting is always kind of a pain, especially without the direct source code, but I'm glad you figured it out.

LaVaughn Haynes
LaVaughn Haynes
12,397 Points

If you want to add an attribute to an element that you will be inserting into the page then you can do that in several ways. Here are a few. If you open the HTML in a browser then you will see that it prints the value of the added attribute on the page to confirm that it was added.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Attribute</title>
 <style>
  div{
    display: inline-block;
    margin: 2px;
    background-color: red;
    width: 100px;
    height: 100px;
    color: white;
    font-size: 50px;
    font-weight: bold;
    line-height: 100px;
    text-align: center;
    font-family: sans-serif;
  }
 </style>
</head>
<body>

<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>

/*-----------------------------------------------
using a string
------------------------------------------------*/
var div1 = '<div data-magnify-src="100"></div>';
//add to page
$('body').html(div1);

/*-----------------------------------------------
using element.data()
------------------------------------------------*/
var $div2 = $('<div></div>');
$div2.data('magnify-src','90');
//add to page
$('body').append($div2);

/*-----------------------------------------------
using an element w/object
------------------------------------------------*/
var $div3 = $('<div></div>', {"data-magnify-src":80});
//add to page
$('body').append($div3);

/*-----------------------------------------------
show data-magnify-src value in the div to verify attribute was added
------------------------------------------------*/
$('div').each(function(){
  $(this).html( $(this).data('magnify-src') );
});

</script>
</body>
</html>
</html>

Hmm... I don't think that will work for what I am trying to do. Ok, so I am building an e-commerce site (you can see the work in progress here) and as you can see, I have my product image and poplets below. Each poplet is an anchor tag that will repopulate the large image inside of the div with the id of #largeimage. I am retrieving the poplets href file source on click, splicing it to add a new data attribute src with the extension of "-large.jpg" and adding that new attribute to the new large image. When the example loads, you will see the first large image loaded will have the attribute 'data-magnify-src="/test_products/test-1-large.jpg" added to it from my previous jquery, but when you select a new poplet, I lose the zoom effect.

The biggest reason I can't auto generate all divs with the attribute already inserted is there will be hundreds of products with at least 2 images each. Plus I want to leave this so I don't need to edit the javascript every time I add a new product or image.

LaVaughn Haynes
LaVaughn Haynes
12,397 Points

After seeing your code, I think the problem is that your poplet function turns this:

<div id="largeimage">
  <div class="magnify"><div class="magnify-lens" style="display: none; top: 46px; left: 401px; background: url(http://sparrowhawkcookware.businesscatalyst.com/test_products/test-1-large.jpg) -931px -200px no-repeat;"></div><img id="catlproduct_10195617" src="http://sparrowhawkcookware.businesscatalyst.com/test_products/test-2.jpg" alt="Test Product 1" border="0" data-magnify-src="/test_products/test-1-large.jpg" style="display: block;"></div>
</div>

into this:

<div id="largeimage"><img src="/test_products/test-2.jpg"></div>

I would change it to update the attributes of the existing elements rather than replace it. You need to update the background: url() of the .magnify div and update the source of the image. You might also want to adjust other attributes such as the alt text of the image as well.

function poplet(e){
  e.preventDefault();
  var imgURL = $(this).attr('href');
  var largeImgURL = '/path/to/large/image.jpg';

  //$('#largeimage').html('<img src="' + imgURL + '">');
  $('#largeimage').find('magnify-lens').css('background', 'url(/path/to/product/img-large.jpg) css-stuff');
  $('#largeimage').find('img').attr('src', '/path/to/product/img.jpg');
}

Good luck

Colin Bell
Colin Bell
29,679 Points

The magnify plugin is what is handling that .magnify div. If you click on a different item, then in the console run:

zoomEffect() followed by $('#largeimage > img').magnify();

everything works. So he just needs to make sure to update the data-magnify-src then run magnify() on the current image on click rather than on $(document).ready()

LaVaughn Haynes
LaVaughn Haynes
12,397 Points

Ahhh, gotcha! Good call. The page loads extremely slowly on my connection so I didn't want to click around.

Colin Bell
Colin Bell
29,679 Points

No worries. I was thinking the same thing as you, but the page source doesn't have the .magnify div. So I decided to tinker around and that seemed to have worked.