I'm trying to make a table of images loaded from a json (not a real json, more like a javascript array) and every time the json changes (when I append a new image to the json file with some script, I want that my table of images to upload as well.
This is the json format:
[{ "image": "images/set_1_UTC+03.jpg", "weight": 101 }, { "image": "images/set_1_UTC+03.jpg", "weight": 102 }, { "image": "images/set_1_UTC+03.jpg", "weight": 103 }, { "image": "images/set_1_UTC+03.jpg", "weight": 104 }]
For this I use isotope. I managed to achieve everything I mentioned above, the only problem is that I wanted to make the images clickable and whenever I click one of the image, to have it in a bigger size and when I click it again to get back to the small size. Here is the code:
<script> var previous = 0; var current = 0; loadJSON(function(response) { // Parse JSON string into object current = JSON.parse(response); }); function loadJSON(callback) { var xobj = new XMLHttpRequest(); xobj.overrideMimeType("application/json"); xobj.open('GET', 'data.json', true); // Replace 'my_data' with the path to your file xobj.onreadystatechange = function () { if (xobj.readyState == 4 && xobj.status == "200") { // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode callback(xobj.responseText); } }; xobj.send(null); } let lengthOfprevious = previous.length; setInterval(function() { loadJSON(function(response) { // Parse JSON string into object current = JSON.parse(response); }); previous = current; if (lengthOfprevious!=current.length){ UpdateBody(lengthOfprevious); } lengthOfprevious = previous.length; }, 5000); function UpdateBody(startIndex) { var newElements = ""; for (let i = startIndex; i < previous.length; i++) { $(document).ready(function () { newElements = ""; newElements += '<div class="photo element-item">' + '<a href="' + previous[i].image +'"><img class="small-image" src="'+previous[i].image+'"/></a>' + '<a class="weight">'+previous[i].weight+'</a></div>'; var $newElems = $(newElements); $('#container').append($newElems).imagesLoaded(function () { $('#container').isotope('insert', $newElems); }); }); } // ============// $(function(){ var $container = $('#container'), $photos = $container.find('.photo'), $loadingIndicator = $('<div class="loading"><span><img src="http://i.imgur.com/IE7iw.gif" /></span></div>'); // trigger Isotope after images have loaded $container.imagesLoaded( function(){ $container.isotope({ itemSelector : '.photo', masonry: { columnWidth: 200 } }); }); // shows the large version of the image // shows small version of previously large image function enlargeImage( $photo ) { $photos.filter('.large').removeClass('large'); $photo.addClass('large'); $container.isotope('reLayout'); } $photos.find('a').click( function() { var $this = $(this), $photo = $this.parents('.photo'); if ( $photo.hasClass('large') ) { // already large, just remove $photo.removeClass('large'); $container.isotope('reLayout'); } else { if ( $photo.hasClass('has-big-image') ) { enlargeImage( $photo ); } else { // add a loading indicator $this.append( $loadingIndicator ); // create big image var $bigImage = $('<img>', { src: this.href }); // give it a wrapper and appended it to element $('<div>', { 'class': 'big-image' }) .append( $bigImage ) .appendTo( $this ) .imagesLoaded( function() { $loadingIndicator.remove() enlargeImage( $photo ); }); // add a class, so we'll know not to do this next time $photo.addClass('has-big-image'); } } return false; }); }); } </script>
The problem is that after setInterval runs once, everything works as expected, when it runs again, the images aren't clickable anymore. If I move the part after the // ============// tag in the for, only the last image is clickable.
I cannot figure out the solution for this (I'm a beginner with javascript). Can someone point me in the right direction?
Update Here you can an archive of the project so that one can run it locally. https://wetransfer.com/downloads/45bf4d0625517a39918060b1075fec1b20180613112617/f7e638
You need to manually copy and pasteduplicate some lines from the data file in order for the demo to work because it searches for the difference of the previous state and the current state of the data file. The problem is that it is clickable at first, and then it's not anymore.
2 Answers
Answers 1
I found the couple of things need to be modified in your code:
- why
$(document).ready
re-iterate more than 1 time - no need to use of
$(function()
As I see the photo class is being generated dynamically on run time and container class is already in DOM, so i have modified click event
$container.on('click', '.photo a', function() {
Edit please note code is not tested, i have just code corrected it.
Final Updated Code is following :
var previous = 0; var current = 0; loadJSON(function(response) { // Parse JSON string into object current = JSON.parse(response); }); function loadJSON(callback) { var xobj = new XMLHttpRequest(); xobj.overrideMimeType("application/json"); xobj.open('GET', 'data.json', true); // Replace 'my_data' with the path to your file xobj.onreadystatechange = function() { if (xobj.readyState == 4 && xobj.status == "200") { // Required use of an anonymous callback as .open will NOT return a value but simply returns undefined in asynchronous mode callback(xobj.responseText); } }; xobj.send(null); } let lengthOfprevious = previous.length; setInterval(function() { loadJSON(function(response) { // Parse JSON string into object current = JSON.parse(response); }); previous = current; if (lengthOfprevious != current.length) { UpdateBody(lengthOfprevious); } lengthOfprevious = previous.length; }, 5000); function UpdateBody(startIndex) { var newElements = "", $container = $('#container'), $photos = $container.find('.photo'), $loadingIndicator = $('<div class="loading"><span><img src="http://i.imgur.com/IE7iw.gif" /></span></div>'); $(document).ready(function() { for (let i = startIndex; i < previous.length; i++) { newElements = ""; newElements += '<div class="photo element-item">' + '<a href="' + previous[i].image + '"><img class="small-image" src="' + previous[i].image + '"/></a>' + '<a class="weight">' + previous[i].weight + '</a></div>'; var $newElems = $(newElements); $container.append($newElems).imagesLoaded(function() { $container.isotope('insert', $newElems); }); } $container.imagesLoaded(function() { $container.isotope({ itemSelector: '.photo', masonry: { columnWidth: 200 } }); }); // shows the large version of the image // shows small version of previously large image function enlargeImage($photo) { $photos.filter('.large').removeClass('large'); $photo.addClass('large'); $container.isotope('reLayout'); } $container.on('click', '.photo a', function() { var $this = $(this), $photo = $this.parents('.photo'); if ($photo.hasClass('large')) { // already large, just remove $photo.removeClass('large'); $container.isotope('reLayout'); } else { if ($photo.hasClass('has-big-image')) { enlargeImage($photo); } else { // add a loading indicator $this.append($loadingIndicator); // create big image var $bigImage = $('<img>', { src: this.href }); // give it a wrapper and appended it to element $('<div>', { 'class': 'big-image' }) .append($bigImage) .appendTo($this) .imagesLoaded(function() { $loadingIndicator.remove() enlargeImage($photo); }); // add a class, so we'll know not to do this next time $photo.addClass('has-big-image'); } } return false; }); }); }
Answers 2
the problem in $photos.find('a').click(
- this bind click to existing items, so new its does not fire click. You should you event delegation&
$('.items_wrap_class').on('click', 'a', function() { /* all existings an new items clicks will fire this */ })
UPD
In your case do delegate #container
.photo a
click handling.
replace $photos.find('a').click( function() { ... })
with
$('#container').on('click', '.photo a', function() { ... })
0 comments:
Post a Comment