Custom jQuery slideshow not appending all data correctly - javascript

I'm a bit rusty with jQuery, but I created a slideshow a couple years ago and I plugged it into a new website I'm building right now and I'm having issues.
The main issue I'm having is I got the background image in the code below to run through the slider correctly, but when I go to run the 'artist_name' data through the same slider code it doesn't loop correctly.
$(document).ready(function() {
// Initial pull in of the projects feature
$.getJSON("index.php/Home/pull_sponsored_videos", function(data) {
// Sets global variables for returned json data
window.$artist_name = data.artist_name;
window.$song_title = data.song_title;
window.$video_uri = data.video_uri;
window.$cover_photo = data.cover_photo;
// Turns returned json data into an array
window.$cover_photo_array = $.map(window.$cover_photo, function(el) { return el; });
window.$artist_name_array = $.map(window.$artist_name, function(el) { return el; });
// Cover Photo Iteration Start
var print_next_sponsored_video_picture_value_index = 0;
var print_next_sponsored_video_picture_value_x;
function print_next_sponsored_video_picture_value() {
$('.sponsored_videos_slider').css('background-image','url('+window.$cover_photo_array[print_next_sponsored_video_picture_value_index]+')');
// Test console
console.log(window.$cover_photo_array[print_next_sponsored_video_picture_value_index])
print_next_sponsored_video_picture_value_index= (print_next_sponsored_video_picture_value_index + 1) % window.$cover_photo_array.length;
}
print_next_sponsored_video_picture_value();
print_next_sponsored_video_picture_value_x = setInterval(print_next_sponsored_video_picture_value, 5000);
// Cover Photo Iteration End
// Artist Name Iteration Start
var print_next_sponsored_video_artist_name_value_index = 0;
var print_next_sponsored_video_artist_name_value_x;
function print_next_sponsored_video_artist_name_value() {
$('.artist_name').text(window.$artist_name[print_next_sponsored_video_artist_name_value_index]);
// Test console
console.log(window.$artist_name[print_next_sponsored_video_artist_name_value_index]);
print_next_sponsored_video_artist_name_value_index= (print_next_sponsored_video_artist_name_value_index + 1) % window.$artist_name.length;
}
print_next_sponsored_video_artist_name_value();
print_next_sponsored_video_artist_name_value_x = setInterval(print_next_sponsored_video_artist_name_value(), 5000);
// Artist Name Iteration End
});
});
In the picture below the 'assets/images/sosagold_pornoflick_coverphoto.png' and 'assets/images/kodakblack_skrilla.png' outputs every time the slideshow changes image, but the output that reads....
Sosa Gold Ft. Ca$H
Kodak Black
... outputs one time to the console, and does not output to the slideshow accordingly, and the last value outputted Kodak Black is what's appended in the jQuery code.
So my question is am I missing anything? Because I've hit a standstill trying to figure out what I am doing wrong.

Related

Retrieving data from an object only works in the original function

I'm having issues retrieving data from an object using JS on my website. I have a third party scrape Instagram posts and provides JSON to my website via a link. I've managed to retrieve this data from the link and manipulate it, but the problem comes when I try to change the displayed image every 5 seconds.
I took the solution from How to change an image every 5 seconds for example? and tried to adapt for my solution, however, I get an error where posts[index] is undefined even though it shouldn't be.
posts = [];
let index = 0;
indexx = 0
$.getJSON('posts.json', function(data) {
$.each(data, function(i, f) {
posts[indexx] = f
indexx = indexx + 1
});
});
console.log(posts) // returns all the posts
window.onload = change();
function change() {
console.log(posts) // Returns the list of posts
console.log(posts[index]) // Returns 'undefined'
console.log(posts[1]) // Returns 'undefined'
$('#instaimg').attr('src', posts[index]["mediaUrl"])
if (index == 5) {
index = 0;
} else {
index++;
}
setTimeout(change, 5000);
}
I'm not sure if I am missing something or whether my lack of JS knowledge is to blame, but if anyone could help it would be appreciated
Several issues with your code:
Your console.log(posts) will show an empty array because the ajax callback has not finished yet => move that inside the .getJSON callback function
You call change recursively every 5 sec, e.g your call stack will grow indefinitely
Use setInterval instead of setTimeout
Start the interval timer inside the .getJSON callback function, so that it starts once the fetched data is ready
Use .push() to add to an array, no need to keep track of the index
Use $(function() { to make sure the DOM is ready before you do any action
You use a hardcoded length 4 for your data length, reference the array size instead
Updated code:
let index = 0;
let posts = [];
$(function() {
$.getJSON('posts.json', function(data) {
//$.each(data, function(i, f) {
// posts.push(f);
//});
// It looks like data is the array you want to use, so:
posts = data;
setInterval(changeImage, 5000);
});
});
function changeImage() {
$('#instaimg').attr('src', posts[index++]["mediaUrl"]);
if(index > posts.length) {
index = 0;
}
}

function increment sync with video (or auto increment)

I'm busy with a webdoc that I'm partially creating on hype, the video are hosted on vimeo (so I need to use the vimeo api for some tasks like seekto) but my difficulties should be limited to js.
the objective is to display a given image at a given time interval of the video.
With my code below, I do get the string "test", "success" and "confirmed success" at the right time in my div id=popimgbox, and I can seek back and forth in the video and still get the right "answear", if I may say so.
Now, I have images that are all stored in the same folder, and all named popimgX.jpg, with X being a number.
I want
to store the URLs of my images in a variable let's say "popimgurl"
that my variable is updated (by a function???) in order to contain the URL of a given immage for a given interval of time of the video
to still be able seekto back and forth in the video and get the right URL at the right time
To do so I created a function increment, and a pair of variable. With the code below, my popimgurl variable is indeed updated once the video reach 3 seconds, but it do not increment only once... untill the video reach 6 seconds, when I want to update my popimgurl variable once again.
I tried to use for with js break and js closure but did not manage for some understandable reasons after thought;
I did quite some try with switch, but I'm stuck with the fact that the case must be string or single numerical value, not numerical interval or comparaison.
thank's in advance for your help :-)
var iframe = $('#vplayer_1')[0];
var player = $f(iframe);
var status = $('.status');
fired = 0;
//my try to sync increment
var dia = (function () {
var n = 0;
return function increment() {return n += 1;}
})();
function dian(){
popimgurl = '${resourcesFolderName}/popimg'+ dia() +'.jpg';
popimgloader = '<img src ="' + popimgurl + '">';
}
// When the player is ready, add listeners for pause, finish, and playProgress
player.addEvent('ready', function() {
status.text('ready');
player.addEvent('pause', onPause);
player.addEvent('finish', onFinish);
player.addEvent('playProgress', onPlayProgress);
});
// Call the API when a button is pressed
$('button').bind('click', function() {
player.api($(this).text().toLowerCase());
});
function onPause(id) {
status.text('paused');
}
function onFinish(id) {
status.text('finished');
}
function onPlayProgress(data, id) {
status.text(data.seconds + 's played');
//my chapters, when I want the img to change within popimgbox
if (data.seconds >= 1) {
popimgbox.innerHTML = "test";
}
if (data.seconds >= 3) {
// popimgbox.style.display = "success"
dian();
popimgbox.innerHTML = popimgurl;
}
if (data.seconds >= 6) {
// popimgbox.style.display = "confirmed success"
dian();
popimgbox.innerHTML = popimgurl;
}
}
PS1: disclamer, I'm a beginer coder, i do my best so excuse my french if my question isn't well formulated or if the answer is somewhere but I was unable to see/understand it
PS2 : i did quite a try with popcornjs, but not way to make it work with vimeoapi and within hype, quite frustrated ;-)
PS3: as this is my first post I would like to thank's you all for the great support available here; I owe you most ;-)
Finally I'll answer myself.
It's a solution that only stand for vimeo, as this is what I use to host my videos, but very little changes have to be done to work with the html5 <video> tag as well.
First you need to define your variables and your intervals:
var intervals =[11.56, 44.08, 115, 125, 127.92, 177.72];
var index;
Then you need to add an event listener timeupdate that return the elapsed time , filter intrevals according to the elapsed time data.seconds or seconds and define the value of index as the indexOf the last entry of your filtered array intervals
player.on('timeupdate', function(data) {
seconds = data.seconds;
index = intervals.indexOf(intervals.filter(function(nb) {
return seconds < nb;
})[0]);
if (diaIndex == -1) {
// do something if seconds > the higher value of your last interval
}
And that's it !
Now for
seconds = [0, 11.56[ --> index = 0
seconds = [11.56, 44.08[ --> index = 1
seconds = [44.08, 115[ --> index = 2
and so on
Now we can use index as a variable for instance to display a given image :
var imgNum = 0;
function diaplayImg(index) {
if(index === imgNum) {
return;
// this will avoid that the same image is releaded on every timeupdate events
}
else {
imgNum =+ index
document.getElementById('myImageWraper').innerHTML = "<img src='img" + imgNum+ ".png'>"
};
}
Don't forget, you need to call the function displayImage() in your timeupdate event listener, it will then be fired every ±250ms but the image won't be reloaded each time
PS : vimeo has realeased its new api between my question and my answer so the question use the old api while the answer use the new one

Scraping dynamically rendered links from an infinite scrollbar in CasperJS

I'm trying to scrape the links on the left sidebar of this page using CasperJS.
The page has hundreds of links in the sidebar, but only loads 20 at a time when you scroll down. This code successfully grabs the first 20 (needs casperjs and phantomjs globally installed to run):
var casper = require('casper').create();
// helper function that gets all of the resume links on the page:
var getAllLinks = function() {
var linksOnThisPage = []
$("a[href^='/ResumeB']").each(function(index, linkDiv) {
$linkDiv = $(linkDiv)
linksOnThisPage.push('http://www.super-resume.com' + $linkDiv.attr('href'))
});
return linksOnThisPage
};
//start casper, go to page, run helper function:
casper.start('http://www.super-resume.com/ResumeBuilder.jtp?query=Database+Administrator', function() {
allLinks=casper.evaluate(getAllLinks)
console.log('number of links found:', allLinks.length);
});
casper.run();
I can make the page scroll down in the actual browser with this:
$('#search-left-inner').scrollTop(10000);
10000 is an arbitrarily big number; every time you run that code in the browser, it loads 20 more links. (Ideally I'd like to be able to grab all at once without having to keep reloading 20 at a time, but that's less pressing for now.)
If I put that line inside the getAllLinks function like so:
var getAllLinks = function() {
$('#search-left-inner').scrollTop(10000);
var linksOnThisPage = []
//etc, etc,
it still only loads 20 links. Many similar posts discuss synchronicity issues, so I've I've tried to get the it to wait for the sidebar to finish loading a few ways, including this:
var getAllLinks = function() {
casper.then(function () {
$('#search-left-inner').scrollTop(100000);
});
casper.then(function () {
var linksOnThisPage = []
//etc. etc.
}
but now for some reason it only finds one link instead of 20.
I presume that if you scroll, it doesn't immediately load the next items, because loading takes time. You need to wait a little after scrolling before you can attempt to scrape all of the elements again.
casper.start(url)
.thenEvaluate(scroll)
.wait(5000, function(){
var links = this.evaluate(getAllLinks);
this.echo(links.length);
})
.run();
If this produces more links, then you can try the next step and that is infinite scrolling until no new elements are loaded. This can be done with asynchronous recursion in CasperJS:
var linkCount = -1;
function getAllLinks() {
var linksOnThisPage = []
$("a[href^='/ResumeB']").each(function(index, linkDiv) {
$linkDiv = $(linkDiv)
linksOnThisPage.push('http://www.super-resume.com' + $linkDiv.attr('href'))
});
return linksOnThisPage
}
function scroll() {
$('#search-left-inner').scrollTop(10000);
}
/**
* Returns true if more elements were loaded that were before
*/
function checkMore(){
var newLinks = this.evaluate(getAllLinks);
var newCount = newLinks.length;
if (linkCount === -1) {
linkCount = newCount;
}
return linkCount < newCount
}
/**
* Executes the a single iteration step and waits for a change in numbers.
* Terminates if there are no changes in 6 seconds.
*/
function step(){
this.thenEvaluate(scroll)
.waitFor(check, step, function _onTimeout(){
var links = this.evaluate(getAllLinks);
this.echo("finished with " + links.length + " links\n\n"+links.join("\n"));
}, 6000);
}
casper.start(url, step).run();
Keep in mind that it makes only sense to use jQuery in the DOM context (page context) which is inside of casper.evaluate(). I suggest that you also read the PhantomJS documentation of that function.

Storing JS counting numbers to continue using HTML5 web storage

I'm trying to store my script that counts numbers starting from 23,000 to always continue to appear it's "live" and always counting using Web Storage. I've tried implementing this and so far, I can't seem to get it to work. What would be the best solution to get this to work and function to always count even when refreshing, etc? I've included my JS Fiddle and code below. Any help is kindly appreciated!!
EDIT: To clarify.. I'm trying to have a "live" counter always going no matter what when you go to the page, refresh it, whatever. It's just always going and getting bigger no matter what just like my script does.. However, everytime I refresh it starts back at 23,000.
HTML
<span id="liveNumbers">23,000</span>
JS
if(typeof(Storage)!=="undefined")
{
setInterval(function(){
random = (Math.floor((Math.random()*2)+1));
var plus = Math.random() < 0.5 ? 1 : 1;
random = random * plus;
currentnumber = document.getElementById('liveNumbers');
var curnum = parseInt(currentnumber.innerHTML.replace(",",""));
document.getElementById('liveNumbers').innerHTML =
commaSeparateNumber(curnum + random);
}, 3000);
function commaSeparateNumber(val){
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
return val;
}
}
else
{
// Sorry! No Web Storage support..
}
Here's my attempt: fiddle
The logic:
On first visit (no localStorage data) the counter is reset to 23000.
Counter runs while page is open.
When closing the page, the current counter value is stored together with the current timestamp (lastSessionEnd).
When user loads the page again, the time that has passed since he closed the page is translated into interval cycles which are passed to the randomRange function and added to the stored counter from the last session.
Here's the code:
if(window.localStorage) {
//configs
var updateInterval = 3000; //ms
function randomRange() {
return Math.floor(Math.random()*3)+1; // [1..3] range
}
var counter = +localStorage.getItem('counter');
if (!counter) { //first load
counter = 23000;
} else { //simulate randomness that would have happened while the user was away from the page
var lastSessionEnd = +localStorage.getItem('lastSessionEnd');
for(var l = Math.floor((getUnixTimeStamp() - lastSessionEnd)*1000/updateInterval); l--;) {
counter += randomRange();
}
}
var liveNumbers = document.getElementById('liveNumbers'); //cache DOM query
function refreshDisplay() {
liveNumbers.innerHTML = commaSeparateNumber(counter);
}
refreshDisplay();
setInterval(function() {
counter += randomRange();
refreshDisplay();
}, updateInterval);
function commaSeparateNumber(val) {
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
return val;
}
function getUnixTimeStamp() {
return Math.floor(Date.now()/1000);
}
window.addEventListener('beforeunload', function() {
localStorage.setItem('counter', counter);
localStorage.setItem('lastSessionEnd', getUnixTimeStamp());
});
} else {
// Sorry! No Web Storage support..
}
NOTE: this is not perfect, here are the caveats:
As it is done purely in the front-end, it is easily hackable by manipulating the localStorage. Don't use this for important stuff.
As it uses the localStorage API, if the user opens the page in more than one browser (or more than one computer/device), each one will have a different counter. Also, cleaning all personal data will reset the counter.
Finally, there's an interval cycle rounding error, it doesn't account for interrupted interval cycles. E.g. the user closes the page midway through an interval cycle, the next time he opens the page that half-cycle will be discarded and a new one starts. I believe this is a small detail which would take more effort to fix than it's worth, but I'll leave that decision and effort to you.

Appending and Preloading Images with JavaScript

I'm in the process of creating a site that preloads several large gifs. Due to the size of the images. I need them all to be loaded before displayed to the user. In the past I have done this numerous times using something basic like this:
var image = new Image();
image.onload = function () { document.appendChild(image); }
image.src = '/myimage.jpg';
However, i'm loading a group of images from an array, which contains the image source url. It should show a loading message and once they have all loaded it show perform a callback and hide the loading message etc.
The code I've been using is below:
var images = ['image1.gif', 'image2.gif', 'image3.gif'];
function preload_images (target, callback) {
// get feedback container
var feedback = document.getElementById('feedback');
// show feedback (loading message)
feedback.style.display = 'block';
// set target
var target = document.getElementById(target);
// clear html of target incase they refresh (tmp fix)
target.innerHTML = '';
// internal counter var
var counter = 0;
// image containers attach to window
var img = new Array();
// loop images
if (images.length > 0) {
for (var i in images) {
// new image object
img[i] = new Image();
// when ready peform certain actions.
img[i].onload = (function (value) {
// append to container
target.appendChild(img[value]);
// hide all images apart from the first image
if (value > 0) {
hide(img[value]);
}
// increment counter
++counter;
// on counter at correct value use callback!
if (counter == images.length) {
// hide feedback (loading message)
feedback.style.display = 'none';
if (callback) {
callback(); // when ready do callback!
}
}
})(i);
// give image alt name
img[i].alt = 'My Image ' + i;
// give image id
img[i].id = 'my_image_' + i
// preload src
img[i].src = images[i];
}//end loop
}//endif length
}//end preload image
It's really weird, I'm sure it should just work, but it doesn't even show my loading message. It just goes straight to the callback.. I'm sure it must be something simple, I've been busy and looking at it for ages and finding it a tad hard to narrow down.
I've been looking over stackoverflow and people have had similar problems and I've tried the solutions without much luck.
Any help would be greatly appreciated! I'll post more code if needed.
Cheers!
If I'm not totally wrong the problem is with you assignment to
// when ready peform certain actions.
img[i].onload = (function (value) {...})(i);
here you instantly call and execute the function and return undefined to the onload attribute, what can not be called when the image is loaded.
What you can do to have access to the value 'i' when the image is loaded you can try something like the following:
onload = (function(val){
var temp = val;
return function(){
i = temp;
//your code here
}
})(i);
this should store the value in temp and will return a callable function which should be able to access this value.
I did not test that if it is working and there maybe a better solution, but this one came to my mind :)
Try this for your onload callback:
img[i].onload = function(event) {
target.appendChild(this);
if (img.indexOf(this) > 0) {
hide(this);
}
// ...
};
Hope you can get it working! It's bed time for me though.
Edit: You'll probably have to do something about img.indexOf(this)... just realized you are using associative array for img. In your original code, I don't think comparing value to 0 is logical in that case, since value is a string. Perhaps you shouldn't use an associative array?

Categories

Resources