AJAX returns previous value in array - javascript

I'm making a website to host artwork. The idea is that when the page loads I have JavaScript run a php file that makes a query to the server to get the names and IDs of the image files (artwork.jpg) and display them as thumbnails on a page.
When you scroll over the thumbnail, the artwork is displayed larger on a different part of the screen and the description, specs, etc for the piece of art fades in. My issue is that when I make this second AJAX call it appends the value of the previously moused over image to the screen and does nothing until you've moused over at least two images.
Here's my code for the first ajax call that appends thumbnails to the page and creates a form with the value of the thumnbnail's id:
function getArtDescriptions()
{
$.post('../../path/to/script/get_art.php', function(json)
{
if (json.art.length > 0)
{
$.each(json.art,function()
{
var info =
'<div class = "thumbnail_box">'
+ '<img src = "images/thumbnails/'
+ this['img']
+ '"id = "'
+ this['ID']
+ '"> '
+ '<form id = "art_descriptions'
+ this['ID']
+ '" '
+ 'name = "art_descriptions'
+ this['ID']
+ '">'
+ '<input type = "hidden" id = "descriptions" name = "descriptions" value = "'
+ this['ID']
+ '"></form>'
+ '</div>';
});
}
}, 'json');
}
And this is the code I'm using to make the second AJAX call that is giving me a problem:
setTimeout(function get_id()
{
var tooltipTimeout;
$(".thumbnail_box img").on("mouseenter", function()
{
tooltipTimeout = setTimeout(details(this.id),0);
console.log(this.id);
});
$(".thumbnail_box img").on("mouseleave", function()
{
hideTooltip();
});
function hideTooltip()
{
clearTimeout(tooltipTimeout);
$(".description").fadeOut().remove();
}
}, 800);
//GRAB DESCRIPTIONS FROM DATABASE AND
function details(art)
{
var formname = "#art_descriptions"+art;
var filename = '../../file/path/to/script/get_descriptions.php';
//console.log($(formname).serialize());
$(".thumbnail_box img").on("mouseenter", function()
{
$.post(filename, $(formname).serialize(), function(json)
{
if (json.descriptions.length > 0)
{
//MAKE SURE TO EMPTY OUT DIV CLASSES FOR EACH TAB
$(".description").empty();
$.each(json.descriptions,function()
{
console.log("art method"+this['ID']);
$(".description").append(this['description']+this['ID']).hide().fadeIn("fast");
});
}
}, 'json');
});
};
When I console.log(this['ID']) in the get_id() method the correct value is displayed in the console, but when I console.log("art method"+this['ID'] in the details method I get a value equal to the previously scrolled over thumbnail's ID. I'd really appreciate any insight on this issue.
Is it something to do with the use of setTimeout()? My code would not run without specifying a timeout for the method. For example if I load the page and then scroll over images with ID's 14 and then 13, my console will display:
14
13
art method 14

The issue is that you are appending more of the same events. After the first mouseenter event occurs the details function is called, which then appends another mouseenter event. So subsequent calls will be doing the same thing. You can see an example of this here: http://jsfiddle.net/6qre72fk/.
var counter = 0;
$('#container1').on('mouseenter', function(){
$('#container2').text('First mouseenter');
appendingAnotherMouseEnter();
});
function appendingAnotherMouseEnter(){
$('#container1').on('mouseenter', function(){
$('#container2').text(counter);
counter++;
});
}
You can see how the counter is incremented several times due to all appended the mouseenter events.

Related

Converting Jquery to Vanilla JS stuck on AJAX

I am trying to convert an older jquery script to vanilla JS.
I have been working through most of them just one by one but am having a problem with the ajax call. Can anyone look at my original file and new file and see what is missing?
I am struggling mostly with converting the initial function calls to vanilla js. If you look at the 2nd code drop there most of the 'jquery-isms' have been rewritten in vanilla js. However I am having trouble converting my $.merge and $.extend actions. Furthermore, converting the $.ajax call to a JS version.
I tried to work on it modularly task by task but still haven't gotten it completely polished.
Jquery
(function($){
$(document).ready(function() {
$.ajax({
url: "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",
type: "GET",
success: function(data) {
console.log("api successfully called")
let path = data.photos.photo
//for each photo, I save the different individual ids into variables so that they can be easily plugged into a URL
for (let i = 0; i < path.length; i++) {
let obj = path[i];
let farm_id = data.photos.photo[i].farm
let server_id = data.photos.photo[i].server
let photo_id = data.photos.photo[i].id
let secret = data.photos.photo[i].secret
//the static address to photos on Flickr is accessed through this address: https://farm{farm-id}.staticflickr.com/{server-id}/{id}_{secret}.jpg
//this variable is the direct link to access photos on Flickr, minus the ".jpg" designation that will be added, according to whether we are trying to access the medium picture or the large picture
let pic_url = "https://farm" + farm_id + ".staticflickr.com/" + server_id + "/" + photo_id + "_" + secret;
//this is the variable that stores the medium jpeg URL
let pic_url_m = pic_url + "_m.jpg";
//this stores an image tag which will be populated with a medium jpeg URL
let pic_img = ('<img src=\'' + pic_url_m + '\' alt = \"pic\" />');
//this appends the var pic_img to the photo_list div as the function loops through
//$('.body').append('#frame');
$('#photo-list').append(pic_img);
//this appends the class "paginate" to each img tag that is formed, ensuring that the the divs get passed to a later function called customPaginate
// $('img').addClass("paginate")
$('#photo-list img').addClass("paginate");
}
//this passes all divs with the class "pagination" to the function customPaginate
$('.pagination').customPaginate({
itemsToPaginate: ".paginate"
});
//when img tags with the class paginate are clicked, the following function is called
$('.paginate').click(function() {
//this variable saves the "src" or URL of (this) which is any element with the class "paginate"
let src = $(this).attr('src');
//this variable takes the "src" variable, slices the last six characters, and replaces it with "_c.jpg", a large version of the image URL
let src_l = src.slice(0, -6) + "_c.jpg";
//gives the "frame img" element a new attribute, which is the large image URL
$('#frame img').attr('src', src_l);
//allows the the "frame img" element to fade into the screen
$('#frame img').fadeIn();
//allows the "overlay" element to fade onto the screen
$('#overlay').fadeIn();
//when the "overlay" element is clicked, both the "overlay" and "frame img" elements
$('#overlay').click(function() {
$(this).fadeOut();
$('#frame img').fadeOut();
//removes the "src" attribute from "frame img", allowing it to be populated by other image URLs next time an image is clicked
$('#frame img').removeAttr('src');
});
});
}
});
});
//this function generates the customPaginate function, which paginates the images 10 to a page
$.fn.customPaginate = function(options)
{
let paginationContainer = this;
let defaults = {
//sets how many items to a page
itemsPerPage : 10
};
let settings = {};
//merges defaults and options into one one variable, settings
$.extend(settings, defaults, options);
//sets how many items will be on each page
let itemsPerPage = settings.itemsPerPage;
//sets which items are going to be
let itemsToPaginate = $(settings.itemsToPaginate);
//determines how many pages to generate based on the amount of items
let numberOfItems = Math.ceil((itemsToPaginate.length / itemsPerPage));
//this ul will contain the page numbers
$("<ul></ul>").prependTo(paginationContainer);
//loops through the ul tag the same number of times as there are pages. in this case, the loop will run 4 times
for(let index = 0; index < numberOfItems; index++)
{
paginationContainer.find('ul').append('<li>'+ (index+1) + '</li>');
}
//ensures that the current page only displays the items that should be on the specific page, and hides the others
itemsToPaginate.filter(":gt(" + (itemsPerPage - 1) + ")").hide();
//locates the first li element, adds activeClass element to it
paginationContainer.find("ul li").first().addClass(settings.activeClass).end().on('click', function(){
let $this = $(this);
//gives current page the activeClass setting
$this.addClass(settings.activeClass);
//takes activeClass setting away from non-current pages
$this.siblings().removeClass(settings.activeClass);
let pageNumber = $this.text();
//this variable designates that items located on the previous page times the number of items per page should be hidden
let itemsToHide = itemsToPaginate.filter(":lt(" + ((pageNumber-1) * itemsPerPage) + ")");
//this function merges itemsToHide and itemsToPaginate that are greater than the product of the pageNumber and the itemsPerPage minus 1, ensuring that these items are hidden from view
$.merge(itemsToHide, itemsToPaginate.filter(":gt(" + ((pageNumber * itemsPerPage) - 1) + ")"));
//designates these items as items that should be shown on the current page
let itemsToShow = itemsToPaginate.not(itemsToHide);
//hides items from other pages and shows items from current page
$("html,body").animate({scrollTop:"0px"}, function(){
itemsToHide.hide();
itemsToShow.show();
});
});
}
}(jQuery));
Vanilla JS (what im still stuck on)
(function($){
document.querySelector(document).ready(function() {
$.ajax({ //need to convert this to JS
url: "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",
type: "GET",
success: function(data) {
console.log("api successfully called")
// ....truncated
}
});
});
$.fn.customPaginate = function()
{
let paginationContainer = this;
let defaults = {
itemsPerPage : 10
};
let settings = {};
//need to convert this extend to JS
$.extend(settings, defaults, options);
let itemsPerPage = settings.itemsPerPage;
// ....truncated
let pageNumber = qS.text();
let itemsToHide = itemsToPaginate.filter(":lt(" + ((pageNumber-1) * itemsPerPage) + ")");
//need to convert this extend to JS
$.merge(itemsToHide, itemsToPaginate.filter(":gt(" + ((pageNumber * itemsPerPage) - 1) + ")"));
});
}
}(jQuery));
First, please see: https://www.w3schools.com/js/js_ajax_intro.asp
Example you might consider.
function getPages(){
const xmlhttp = new XMLHttpRequest();
xmlhttp.onload = function() {
// Everything you want to do with the data
// this.responseText.photos.photo
}
xmlhttp.open("GET", "https://api.flickr.com/services/rest/?method=flickr.galleries.getPhotos&api_key=*PRIVATE*c&gallery_id=72157720949295872&per_page=10&format=json&nojsoncallback=1",);
xmlhttp.send();
}

How to access an element of a dynamically loaded page

I have a div in a page called firstpagemidle.php,
DIV id="news" data-pageNum_rsnews="1" data-totalRows_rsnews="9" class="new">
And I load this page in another page by this code:
$('#bigmidlecontent').load("../"+tab+"/"+stab+"midle.php",'',loadboth);
And now I want to access the variable PageNum from the page that is already loaded. How can I do that?
I use the function loadboth() exactly the same way as friends mentioned, but it didn't work.
After that I change the ID pagenum_rsnews to (pagenum) and now it works.
You'd do that in the callback function you're referencing, as the elements would be loaded then
$('#bigmidlecontent').load("../"+tab+"/"+stab+"midle.php",'',loadboth);
function loadboth() {
var pagenum = $('#news').data('pageNum_rsnews'); // 1
}
jQuery apparently converts data to lower case:
$('#bigmidlecontent').load("../" + tab + "/" + stab + "midle.php", '', loadboth);
function loadboth() {
var pagenum = $('#news').data('pagenum_rsnews'); // 1
}
For extracting all data, use:
$('#bigmidlecontent').load("../" + tab + "/" + stab + "midle.php", '', loadboth);
function loadboth() {
var pagenum = $('#news').data(); // {totalrows_rsnews: 9, pagenum_rsnews: 1}
}

How to use sharethis with Ajax

I am ajaxing in new buttons after each successful http request.
//Remove events and items
$('#sthoverbuttons-chicklets span').remove();
I then add new items with new events in by passing an object into stwidget.
See here documentation for sharethis: http://support.sharethis.com/customer/portal/articles/475079-share-properties-and-sharing-custom-information#Dynamic_Specification_through_JavaScript
//Finish with share buttons
wyrAjax.sharethis.finishAddingShareButton();
wyrAjax.sharethis = {
//Grab the current share height so we can keep it this height when we remove all the items
shareThisHeight:null,
init:function () {
//If the height has not been set set it
if(wyrAjax.sharethis.shareThisHeight===null){
wyrAjax.sharethis.shareThisHeight = $('#sthoverbuttons').outerHeight();
}
//Set up elements so that we can use them as ID's
$('.sthoverbuttons-chicklets').attr('id', 'sthoverbuttons-chicklets');
if (!$('#shareLoading').length) {
$('#sthoverbuttonsMain').append('<div id="shareLoading"><img src="/img/loading.gif" style="position: absolute; top: 50%;left: 37%"></div>');
}
},
shareTypes:function(){
var array = [];
array[0]={
"service":"facebook"
};
array[1]={
"service":"twitter"
};
array[2]={
"service":"delicious"
};
array[3]={
"service":"googleplus"
};
array[4]={
"service":"reddit"
};
array[5]={
"service":"tumblr"
};
array[6]={
"service":"stumbleupon"
};
array[7]={
"service":"digg"
};
array[8]={
"service":"sharethis"
};
return array;
},
startGettingShareButton:function () {
//First we run a quick check to see if the elemnts have ID's
wyrAjax.sharethis.init();
//Now lets fade out and clean up all the shares so we can add new shares in.
$('#sthoverbuttons-chicklets').hide();
$('#sthoverbuttonsMain').height(wyrAjax.sharethis.shareThisHeight);
wyrAjax.sharethis.addLoadingToShare();
},
addLoadingToShare:function () {
$('#shareLoading').show();
$('#sthoverbuttons-chicklets span').off().remove();
},
finishAddingShareButton:function () {
$('#shareLoading').hide();
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
wyrAjax.sharethis.addShareThisButton(value);
});
$('.sthoverbuttons-chicklets').show();
},
addShareThisButton:function (object) {
stWidget.addEntry({
"service":object.service,
"element":document.getElementById('sthoverbuttons-chicklets'),
"url":"http://www.wouldyourathers.co.uk/question/" + wyrAjax.questionDetails.id,
"title":"Would You Rather | " + wyrAjax.questionDetails.q1,
"type":"large",
"text":"Would You Rather " + wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2,
"summary":wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2
});
}
};
When I click one of the newly added buttons it will go to for example the share feature of twitter, but it will also bring up for some reason Facebook's share.
I believe I want to remove all events on the spans before I re-add them.
So the problem i was having is that sharethis doesn't want you remove the share items. Sharethis stWidget.addEntry doesn't want to you to add new dom items, it wants you to replace the current share butons already on the page.
With this in mind i edited my code to add ID's to all buttons already shared:
//Give all share buttons ID's
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
$('.st_'+value.service+'_large').attr('id','st_'+value.service+'_large');
});
Then i used Sharethis's addEntry to just replace the existing button.
wyrAjax.sharethis = {
//Grab the current share height so we can keep it this height when we remove all the items
shareThisHeight:null,
init:function () {
//If the height has not been set set it
if(wyrAjax.sharethis.shareThisHeight===null){
wyrAjax.sharethis.shareThisHeight = $('#sthoverbuttons').outerHeight();
}
//Set up elements so that we can use them as ID's
$('.sthoverbuttons-chicklets').attr('id', 'sthoverbuttons-chicklets');
if (!$('#shareLoading').length) {
//Give all share buttons ID's
var shareItems = wyrAjax.sharethis.shareTypes();
$.each(shareItems,function(key, value){
$('.st_'+value.service+'_large').attr('id','st_'+value.service+'_large');
});
$('#sthoverbuttonsMain').append('<div id="shareLoading"><img src="/img/loading.gif" style="position: absolute; top: 50%;left: 37%"></div>');
}
},
shareTypes:function(){
var array = [];
array[0]={
"service":"facebook"
};
array[1]={
"service":"twitter"
};
array[2]={
"service":"delicious"
};
array[3]={
"service":"googleplus"
};
array[4]={
"service":"reddit"
};
array[5]={
"service":"tumblr"
};
array[6]={
"service":"stumbleupon"
};
array[7]={
"service":"digg"
};
array[8]={
"service":"sharethis"
};
return array;
},
startGettingShareButton:function () {
//First we run a quick check to see if the elemnts have ID's
wyrAjax.sharethis.init();
//Now lets fade out and clean up all the shares so we can add new shares in.
$('#sthoverbuttons-chicklets').hide();
$('#sthoverbuttonsMain').height(wyrAjax.sharethis.shareThisHeight);
wyrAjax.sharethis.addLoadingToShare();
},
addLoadingToShare:function () {
$('#shareLoading').show();
},
finishAddingShareButton:function () {
//Remove the loading.gif
$('#shareLoading').hide();
//grab array of different share types
var shareItems = wyrAjax.sharethis.shareTypes();
//Loop through
$.each(shareItems,function(key, value){
wyrAjax.sharethis.addShareThisButton(value);
$('#st_'+value.service+'_large > span:first-child').remove();
});
$('.sthoverbuttons-chicklets').show();
},
addShareThisButton:function (object) {
stWidget.addEntry({
"service":object.service,
"element":document.getElementById('st_'+object.service+'_large'),
"url":"http://www.wouldyourathers.co.uk/question/" + wyrAjax.questionDetails.id,
"title":"Would You Rather | " + wyrAjax.questionDetails.q1,
"type":"large",
"text":"Would You Rather " + wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2,
"summary":wyrAjax.questionDetails.q1 + " or " + wyrAjax.questionDetails.q2
});
}
};
Hopefully somebody can find this helpful.

jQuery - removing an alert stop code from working

The code below works, but there is an issue with it.
That issue is that unless the alert(this.href); - (about line 11) is in the code the following function does not work.
//There are pages which make up 2 chapters in this content
//We shall attempt to grab all the links from these pages
var c;
var chapters = new Array();
chapters[0] = "original/html/0/ID0EFJAE.html";
//Loop through each page of links
$.each(chapters, function(key, value) {
$("#theContent").append("<div class='chapterindex" + key + "'>working</div>");
$(".chapterindex" + key).load(value + " .content");
alert(this.href);
$(".chapterindex" + key + " div.link a").each(function(intIndex) {
alert(".chapterindex" + key);
});
});
If I take the first alert out of line 11 then the last alert doesn't fire. What am I doing wrong?
The delay that the alert is causing is allowing the data in your load call to load. I suspect that when you remove the alert the data does not load in time.
Try using a callback with your load call, something like (code not tested) -
$(".chapterindex" + key).load(value + " .content",function () {
$(".chapterindex" + key + " div.link a").each(function(intIndex) {
alert(".chapterindex" + key);
});
});
The first alert is probably giving the load function enough time to finish so when you take it out the load function is not done when its trying to fire your second alert.

Dual Twitter feeds with jquery fadeIn and setInterval

I am making a project that shows two opposite views in two divs side-by-side. I have everything set up so the Tweets show in their respective div, but I'd like to make them both fade in, one tweet at a time (both sides can fade in at once, I don't mind that).
My Tweets are coming from an array, and I'm currently using the following code to push updates to the div:
for(var i=0; i < tweets.length; i++)
{
$("#proTweetList").prepend("<li><img src='" + tweets[i].profile_image_url + "' />" +
tweets[i].text+"</li>");
}
and
for(var i=0; i < tweets.length; i++)
{
$("#antiTweetList").prepend("<li><img src='" + tweets[i].profile_image_url + "' />" +
tweets[i].text+"</li>");
}
I found a great example on Stackoverflow, which is as follows:
var x=0; // The corner counter
function fading() {
$("#corner"+(++x)).fadeIn(2000); // Fade in the current corner
if (x==4) { // Last image to be faded in?
clearInterval(); // Stop interval
}
}
$(document).ready(function(){
setInterval("fading()",1000); // Call function every second
});
but I am very new to JQuery and cannot figure out how to translate this code into getting LI items in TWO different divs to fade in.
-- Derek
I would do something like this:
for(var i=0; i < tweets.length; i++)
{
var $item = $("<li style='display:none;'><img src='" + tweets[i].profile_image_url + "' />" +
tweets[i].text+"</li>");
$("#proTweetList").prepend($item);
$item.fadeIn(2000);
}
Didn't test that piece of code though, but I think it will work. This will create the list item within a jQuery object($item), that way you can use functions like fade on it directly.
You could do this with a simple plugin. This way you can attach the behaviour to as many divs as you like. I've written a very simple one (untested sorry) that may help:
;(function ($) {
$.fn.loadtweets = function (options) {
var settings = $.extend(
{
fadeTime : 1000,
delay: 2000,
tweets : array()
},
options
);
return this.each(
function() {
var _this = $(this),
tweets = settings.tweets,
index = 0;
var loadTweet = function() {
if (tweets.length > index) {
_this.prepend("<li><img src='" + tweets[index].profile_image_url + "' />" +
tweets[index].text+"</li>").fadeIn(settings.fadeTime);
index++;
setTimeout(loadTweet, settings.delay);
}
}
loadTweet();
}
);
};
})(jQuery);
You would call this plugin by going (I assume you have an array of tweets for each div):
$('#proTweetList').loadtweets({'tweets': proTweetsArray});
$('#antiTweetList').loadtweets({'tweets': antiTweetsArray});

Categories

Resources