Applying a lightbox to JSON data

Hi, I’m having difficulty figuring out how to create and apply a lightbox to JSON data. I’ve created a lightbox before, but for whatever reason, I’m having trouble doing the same with JSON data. Please help. Below, I’ve provided my HTML, CSS, and JavaScript. I commented the areas where I attempt to create the overlay. Also, here is an example of the JSON data that I’m trying to pull from: https://api.spotify.com/v1/search?q=muse&type=album

Thanks for your time.

HTML

<!DOCTYPE html>
  <html>
    <head>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
      <script src="script.js"></script>
      <link rel="stylesheet" type="text/css" href="styles.css">
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    </head>
    <body>
      <div class="top">
        <h1>Spotify Song Search</h1>
        <form id="search-form">
          <input type="search" placeholder="Search for a album or band" id="song">
          <button type="submit" id="search">Search</button>
        </form>  
      </div>
      <div id="music"> <!-- Start of overlay attempt -->
        </div>
      </div>
    </body>

  </html>

CSS

body {
background-color:

}

.top {
text-align: center;

}

#music {
margin-left: 40px;
margin-right: 40px;
margin-top: 40px;

}

.album {
display: inline-block;

}

li {
list-style: none;
padding: 10px;
}

img {
width: 200px;

}

input {
width: 400px;
height: 30px;
}

// Start of overlay attempt

#overlay {
background-color: rgba(0,0,0, 0.7);
width: 100%;
height: 100%;
position: absolute;
top: 0;
left:0;
display: none;
text-align: center;
}

#overlay img {
margin-top: 10%;
height: 360px;
width: 360px;
}

#overlay p {
color: white;

}

JavaScript

$(document).ready(function() {
	$('form').submit(function(evt) {
		evt.preventDefault();
		// var $searchField = $('#song');
		var spotifyAPI = "https://api.spotify.com/v1/search" // needs end point
		// var albums = $searchField.val();// Specifies type of user info to be retrieved and sent to Spotify API
		var spotifyOptions = {
			"type": "album",
			"query": $("#song").val(),
			"limit": "12"

		}; // Requests data from spotify API. Must be a JavaScript Object
		$.getJSON(spotifyAPI, spotifyOptions, displayAlbums); // Currently, these are only placeholders. The variables inserted as arguments have not been defined as variables
		function displayAlbums(data){
				console.log(data);
			var albumHTML = '<ul>'; // Opening ul tag to hold a single album result
			$.each(data.albums.items, function(i, album){
				albumHTML += '<div class="album col-md-3" album-id="' + album.index + '">';
				albumHTML += '<li>'; // You may need to use bootstrap to style array items correctly
				albumHTML += '<a href="#">';
				albumHTML += '<img src="' + album.images[0].url + '" alt="' + album.artists.name + '">';
				albumHTML += '</a>';
				albumHTML += '</li>';
				albumHTML += '</div>';
				return albumHTML;
			});

				albumHTML += '</ul>';
				$('#music').html(albumHTML);

			};

/* Start of overlay attempt */
			var $overlay = $('<div id="overlay"></div>');
			var $image = $("<img>");
		var $caption = $("<p></p>");			

			$overlay.append($image);
			$overlay.append($caption);

			$("body").append($overlay);

			$("#song a").click(function(event){
				event.preventDefault();
				var imageLocation = $(this).attr("src"); // May need to specify a second argument
				$image.attr("src", imageLocation);
				$overlay.show();

				var captionText = $(this).children(img).attr("alt");
				$caption.text(captionText);
			});	

			$overlay.click(function(){
				$overlay.hide();
			
			});

		});

	});

Hey, so you’re trying to pull JSON data from the Spotify API, parse the results and display them in a lightbox. Did I get that right?

If so, can you make a JSFiddle demonstrating this. You could hardcode the JSON (as this sin’t really part of the problem you’re trying to solve).

1 Like

There are a couple of issues… first of all, an element #song does not exist – did you mean #music? This still wouldn’t work though as your links are inserted dynamically after the listeners have been attached (to no element, actually); so you’ll either have to bind them after the list has been generated, or use event delegation like

$("#music").on('click', 'a', function (event) { /* etc... */ })

Within the handler function, this refers to the link being clicked; but you can get the src attribuite of the img child like

var imageLocation = $('img', this).attr('src')

And another small thing is the missing quotes around the img selector a bit below. Oh and BTW, wrapping the li elements in a div is not valid HTML; the li elements must be direct children of a ul element.

Ok. I’ll do that today and post the link in this topic.

the line with the input tag in the HTML code has the id of song.

 <div class="top">
        <h1>Spotify Song Search</h1>
        <form id="search-form">
          <input type="search" placeholder="Search for a album or band" **id="song"**>
          <button type="submit" id="search">Search</button>
        </form>  
      </div>

Just below this text, the opening ul tag begins. And, at the very end of this pasted JavaScript code is the closing ul tag. So yea, as far as I can tell, the li tags are nested inside ul tags.

var albumHTML = '<ul>'; // Opening ul tag to hold a single album result
			$.each(data.albums.items, function(i, album){
				albumHTML += '<div class="album col-md-3" album-id="' + album.index + '">';
				albumHTML += '<li>'; // You may need to use bootstrap to style array items correctly
				albumHTML += '<a href="#">';
				albumHTML += '<img src="' + album.images[0].url + '" alt="' + album.artists.name + '">';
				albumHTML += '</a>';
				albumHTML += '</li>';
				albumHTML += '</div>';
				return albumHTML;
			});

				albumHTML += '</ul>';
				$('#music').html(albumHTML);

All that being said though, I think you’re right that something needs to change either with the event handler with #music and/or the imageLocation. I have the overlay showing up for me now and an img, but the same img is shown each time instead of the image for the respective album that I click on. I’ll post into JSFiddle.

Ok. Here’s the JSFiddle: https://jsfiddle.net/z8zkrwks/. Maximize the results window if you want to see how the results are arranged when run.

Thanks for all of your help so far. I’m definitely making progress. So, if you search an album, it will show the various albums based on what you search for. Right now, no matter what album you click on, only an overlay of the first album image will show. So, if you click on the 2nd, 3rd, 4th album image (or even any album image after that), an overlay for the first album image will be shown by default. This is not ideal. If the 2nd album image result is clicked, I want to show an overlay of THAT album image and only that one.

Further, if you click anywhere, even a blank space, an overlay of the first album image will be shown. So, it sounds like I’m simply not targeting any of the album images upon being clicked. Let me know what you guys think. Thank you.

You’re binding the click handler to the #music element, so $('img', this) refers to all images in the list; and jQuery will just return the attr() of the first match then. As I suggested above, you could use event delegation here.

2 Likes

Ok. I’ll try that m3g4p0p. I don’t know what event delegation is, but I’ll look into the link that you provided on it. Thanks.

Alright. Thanks, m3g4p0p. You’re awesome. Now, only the images for the respective albums that are clicked are showing up.

To be honest, I’ll probably have to read about event delegation more cause I still don’t really understand it all that well, but it’s working. So, I’m happy about that at least.

So did you get your problem solved? Or is there something that’s stlll not working as desired?

And FWIW, event delegation isn’t tricky. It just involves you binding an event handler to a parent element and using that to deal with clicks (or whatever). You would typically do this when you have a very large collection of elements (e.g. a list) — you would bind one handler to the list and delegate the clicks as appropriate, as opposed to binding 100 or 1000 or however many handlers to the individual list elements.

Another popular use case is for attaching events to dynamically inserted content. This content isn’t present when the page is loaded (so you can’t do anything with it). Instead you attach to a parent element (even “body” or “document”) that is and handle the events accordingly.

Here’s an article on the subject: https://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/

1 Like

Hey Pullo, thanks for the article.

I would say that my problem for this topic is solved. I do have one more task related to JSON data that I want to take care of, but it is not directly related to the topic of this post. So, it sounds like it would be best if I created a new post for it.

Thanks for asking, Pullo.

1 Like

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