Click Thumbnail, Display Large Image Javascript

Notice that we extract the needed data from the clicked thumbnail? This is a handy approach since it does not rely on a separate data structure to drive the code. It is self-contained.

2 Likes

So for fun, I thought I would try to convert the javascript code to Jquery so
what do u think?

these two parts i wasn’t too sure how to convert but I tried anyway
$(this).click(function(e) {
e = e || window.event;
return e.target || e.srcElement;
})

let target = $(event.target);
‘use strict’;

$(document).ready(function() {
  function thumbsHandler(e) {
    let views = $('#views');
    let target = $(event.target);
    let choice = target.attr("src");
    let title = target.attr("title");

    $("<img>");
    views.attr('alt');
    views.attr('choice');
    views.attr('title');
    views.html('');
    views.append(views);
  };


  let thumbs = $('#thumbs');


  thumbs.on('click', thumbsHandler);


  $(this).click(function(e) {
    e = e || window.event;
    return e.target || e.srcElement;
  })


});
1 Like

When we have useful JS that does its job, jQuery is not needed to improve it. In fact, it can’t. It will only slow it down.

2 Likes

I would use to put a custom attribute on img tag that will contain the full image path.

<img src="smallelephant.jpg" big-img="fullelephant.jpg"/> 

Then on click event I will simply change the src & big-img values.

1 Like

so using <a></a> is not an option

2 Likes

I get what you are saying but I was just trying to see if I can

1 Like

So, does it work? I can see a number of reasons why it won’t. I’d like to help more but don’t find any desire to since it looks like you are not respectful of your code sources. There is a reason for writing attribution comments in the code–it wasn’t mine, but someone else’s. It may only be four or five lines, but it is the vital component. Not giving credit to its author is theft.

2 Likes

To me it makes more sense, and means less work to have both images with the same name and different server directories.

2 Likes

oh okay, I’m sorry I didn’t mean for it to come off as if I was trying to steal your code and pass it as my own. I was trying to see I can turn it into jquery that’s all. I never said the code was mine. I’m sorry I had no intention of doing that so. I was just trying to play around with the code, but if you feel like I’m doing what you said I was doing just tell me and I’ll never ask again. I’m just a beginner and I thought me playing around with the code was so okay but if you wish I will take this down never ask again.

1 Like

I’m so sorry, I really am.

1 Like

Just don’t forget to credit your sources. Two reasons… One it is theirs (they want us to use it), and two, it gives you a record of source and description, discussion, explanation, etc. so that months down the road you can make sense of it and read up on it again.

No one is accusing you of theft. Just warning that good habits now lead to less confusion later, and all parties involved are noted. We borrowed that code from Sitepoint, so they should get the credit. As for me, I don’t have a big deal to prove and my code is only published here. If you are using it in your own projects, credit CC by linking back to the topic you borrowed it from (in a comment).

That aside, let’s look at why your code won’t work…

Okay, now what? That’s a joke. Nothing happens. This is a blank stare. To emulate the above example, it should read…

let view = $('<img/>');

Now we have an IMG element waiting in memory that we can reference.

The attribute settings that follow belong to the image, not the container.

view.attr('alt', "");
view.attr('src', choice);
view.attr('title', title);
views.html('');
views.append(view);

Note the last line. We append the image to the container. Your line above creates a circular reference…

views.append(views);

We cannot append an object to itself.

That is a standalone function, not a handler, per se.

const getEventTarget = e => {

};

It can exist outside of your jQuery wrapper in the global namespace. To keep from polluting the global namespace, it can be written inside your wrapper, but still as a function. It has no context but the event object passed into it. There is no this and there is no associated event. It can take any event object. Its sole purpose is to read the target attribute of the event object and return it. If you have not read up on this function, then now would be a good time to go to the article and read it.

This should be,

let target = getEventTarget(e);

We captured the event object in e, the parameter of thumbsHandler, and pass it to the function. The return value will be the object that was clicked. Now we can access its attributes.

Recall that this is long URL, and all we want is the name of the image. If you read my example you will see where we trace through the URL to the last / and then truncate everything to the left, including the /, leaving only the image name. In the next line we fashion a new URL from that, re-inserting the host path with a new directory name followed by the image name.

choice = choice.substring(choice.lastIndexOf('/') + 1);
choice = `${host}bigImage/${choice}`;

This object can be queried at the start of the session and cached. To protect it we declare it as a const. Like the function we talked about earlier, it is free-standing and does not belong in any functions. The same goes for the thumbs object.

const views = $('#views');
const thumbs = $('#thumbs');

If we study jQuery’s .on method a little deeper we find that it has event delegation built in. If this is properly wired we don’t need the getEventTarget function. I’ll leave you to read up on this and we can revise the code once you’ve done that.

A couple of considerations when working with jQuery…

  1. It is not meant to replace valid, working JS, but simplify the messy bits. Ideally a program should be written in vanilla JS for the most part since it is much faster. Only use jQuery where it makes sense to use it.
  2. Help your reader and yourself to identify jQuery objects in the code. It has no special meaning, but when the $ is prefixed to a variable name it tells the reader that it is a jQuery object.
  3. Organize your code so that constants, variables, and functions appear at top, followed by handlers and other code, followed by event listener attachments.

Following is a mock up of the ideas presented above. It’s not tested but it should run as long as jQuery is available.

'use strict';
const host = "http://fiddle.jshell.net/_display/";
const $views = $('#views');
const $thumbs = $('#thumbs');
const $view = $('<img/>');
//https://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/
const getEventTarget = e => {
  e = e || window.event;
  return e.target || e.srcElement;
};
const thumbsHandler = e => {
  let target = getEventTarget(e);
  let choice = target.src;
  let title = target.title;
  choice = choice.substring(choice.lastIndexOf('/') + 1);
  choice = `${host}bigImage/${choice}`;
  $view.alt = "";
  $view.src = choice;
  $view.title = title;
  $views.html('');
  $views.append($view);
};
const main = function() {
  $thumbs.on('click', thumbsHandler);
};
$(document).ready(main);

Be sure the script tag is at the end of the body, not in the head.

Edit

Tested and doesn’t work. Contains errors. Trying to find an environment to run and test in. Won’t run in Codebits, or on repl . it.

2 Likes

After debugging, and a lot of rethinking, this is what I came up with.

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>thumb viewer</title>
    <link href="index.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div id="thumbs">
      <img src="thumb/Snow.jpg" alt="" title="Snow">
      <img src="thumb/enter.jpg" alt="" title="Enter">
      <img src="thumb/one.jpg" alt="" title="One">
      <img src="thumb/Birds.jpg" alt="" title="Birds">
      <img src="thumb/lake.jpg" alt="" title="Lake">
    </div>
    <div id="views"></div>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    <script src="index.js"></script>
  </body>
</html>
index.js
'use strict';

const main = function() {
  const host = "";
  const $views = $('#views');
  const $thumbs = $('#thumbs');
  const thumbsHandler = function () {
    let choice = $(this).attr('src');
    let title = $(this).attr('title');
    choice = choice.substring(choice.lastIndexOf('/') + 1);
    choice = `${host}bigImage/${choice}`;
    let $view = $('<img alt=""/>');
    $view.attr({'src': choice, 'title': title});
    $views.html('');
    $views.append($view);
  };
  $('#thumbs').on('click', 'img', thumbsHandler);
};
$(document).ready(main);
index.css
#thumbs {
  margin: 1em auto;
}
#views {
  width: 90%;
  height: 300px;
  margin: 1em auto;
  padding: 1em 0;
  border: 1px dotted black;
}
#thumbs{
  width: 92%;
}
#thumbs img {
  display: inline-block;
  width: 100px;
  height: 100px;
  border: 1px solid black;
}
#views img {
  display: block;
  width: 400px;
  height: 300px;
  margin: 0 auto;
  border: 1px solid black;
}

In this demonstration we apply jQuery delegation and get to use $(this) to represent the target element. If we peer under the hood of jQuery I’m betting that the getEventTarget() is buried in there somewhere. But the power is abstracted into that simple event listener, on().

We single out the parent element to which is bound the event listener. A click event generates an event object, and among the properties of that object is information about the target. Same as before, except now we have a context object in the handler, the img that was clicked. That’s what $(this) is.


Now we can refine this even more by moving two lines out the function:

let $view = $('<img alt=""/>');

becomes,

const $view = $('<img alt=""/>');

and we append it to the view immediately so that the placeholder border appears in the browser. When we click on a thumbnail. only the attributes are manipulated and we no longer have to create the img element in the handler. We also don’'t need to clear the innerHTML. So the code comes down to this…

'use strict';

const main = function () {
  const host = "";
  const $views = $('#views');
  const $thumbs = $('#thumbs');
  const $view = $('<img alt=""/>');
  $views.append($view);
  const thumbViewer = function () {
    let choice = $(this).attr('src');
    let title = $(this).attr('title');
    choice = choice.substring(choice.lastIndexOf('/') + 1);
    choice = `${host}bigImage/${choice}`;
    $view.attr({'src': choice, 'title': title});
  };
  $('#thumbs').on('click', 'img', thumbViewer);
};
$(document).ready(main);

In your fiddler environment be sure to locate the folder where your images are and insert the path URL into the host value. It must be a string in the code so be sure to leave the quotes.

The CSS also uses arbitrary dimensions. Reset them to match your thumbnails. Also adjust the views div to suit.

A Codebit of the demo is here… https://www.codecademy.com/mtf/codebits/w5CgsK

There are no images, per se, but if you click on a thumbnail then hover on the viewer it will display the tooltip. I have reproduced this code on my own machine with a few images and it works flawlessly. An imageless version is up and running on REPL .IT

https://repl.it/Nz1F

2 Likes

A post was split to a new topic: jQuery Thumbnail Viewer demo

The codebit linked above has been updated to include images stored on CC’s CDN so as to match the domain. Now it is possible to see the demo in action.

2 Likes

Some hours ago we had this…

const views = {
  data: {
    thumb: URI,
    view: URI
  },
  // ...
};

const host = "https://codecademy-discourse.s3.amazonaws.com/original/5X/";
const main = function() {
  const $views = $('#views');
  const $thumbs = $('#thumbs');
  $thumbs.children().each(function () {
    let key = $(this).attr('data');
    $(this).attr({'src': `${host}${views[key].thumb}`})
  });
  const $view = $('<img alt=""/>');
  $views.append($view);
  const thumbViewer = function () {
    let choice = $(this).attr('data');
    let title = $(this).attr('title');
    choice = views[choice].view;
    choice = `${host}${choice}`;
    $view.attr({'src': choice, 'title': title});
  };
  $('#thumbs').on('click', 'img', thumbViewer);
};
$(document).ready(main);

and after some more refactoring we get to this…

const main = () => {
  const $views = $('#views');
  const $thumbs = $('#thumbs');
  const $view = $('<img alt=""/>');
  
  $thumbs.children().each(function () {
    $(this).attr('src', host + views[$(this).attr('data')].thumb);
  });
  
  $view.attr({
      'src': host + views[$thumbs.children().eq(0).attr('data')].view,
      'title': $thumbs.children().eq(0).attr('title')
  });
  $views.append($view);
  
  const thumbViewer = function () {
    $view.attr({
        'src': host + views[$(this).attr('data')].view,
        'title': $(this).attr('title')
    });
  };
  $('#thumbs').on('click', 'img', thumbViewer);
};
$(document).ready(main);

The key to this approach is the IMG tags in the HTML.

<img src="" alt="" title="Avonglen School marker" data="avonglen"/>

The program populates the SRC attributes using its data value as a key in the views object. This was necessary since the URI’s are hashes. In the earlier example we fashioned the URL from the thumbnail src, but that is not possible here since there is no relation between the thumbnail URI and the view URI. The only thing in common is the host path.

This finished version also preloads the first image into the viewer.

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.