Successive Ajax calls in Javascript For Loop - Playlist - javascript

Please Help!! I'm seeing a lot of mixed results when I search for this, none of them which apply here. My goal is basically to turn a randomly and dynamically populated list of songs into a playlist, so that each song plays one after the other, and the iframe for youtube or soundcloud is ajaxed in in sequence.
I have a simple list of songs that is populated from the youtube and soundcloud api's, which is output to an unordered list. As each song in the list is loaded into the browser its anchor tag is given an id.
//List Item
echo "<a id=\"" . $i . "\" href=\"javascript:void(0)\" onclick=\"play_clicked('youtube',".$i.",".$song_count.")\">
<li class = \"song\">";
The first song in the list gets id 0, the second, 1 and so on. The media id of each song is also "pushed" onto a javascript array one at a time as they load, so that the id of the song's anchor tag corresponds to the key in the array where the song's media id is held.
echo
'<script type="text/javascript">
track_id_array.push("'.$vid_id.'");
</script>';
I've created a javascript function that is called when a song is clicked:
function play_clicked(api_type,clicked_key,song_count)
The function receives parameters for api type - soundcloud or youtube, the anchor id, or array key where the clicked media id is held, and then how many songs are in the list. There is a for loop to iterate through the array of media ids:
for (var i=clicked_key; i<=song_count; i++){
So I am starting the loop at whatever the id of the clicked song was, and the goal is to continue to iterate through the songs that follow after the clicked song. First I check if the media id exists in the array:
if(window.track_id_array[i])
If this exists, it should hold the media's id - example youtube id - 6_8ZZtL6qmM. Then I check whether it is a soundcloud or youtube song, and depending on which, I send the media id with ajax to a php script that will embed the id into the html5 iframe embed widget for either soundcloud or youtube, something like this:
$vid_id = $_GET[id];
//Youtube player embed
echo '<iframe width="498" height="280" src="http://www.youtube.com/embed/'.$vid_id. '?autoplay=1" frameborder="0" allowfullscreen></iframe>
';
and then I return this html to a div inside my main page, and the song will play in the corresponding widget. The way I had imagined accomplishing my goal of a playlist is to start with the clicked song's id/key in the loop, retrieve the media id for that key from the array, check the api type, make the proper ajax call, set a timeout for the length of the song, and then have the loop continue to the next key in the array after the song was finished playing, so that it would start the process over with the next song in the list, or id in the array.
Javascript is really not my strong suit and I hate that I have to use client-side code for this. My question is, is the method I described here possible, or am I going about this the wrong way? I only want to make the ajax calls one after the other in the loop, so they won't be happening at the same time. Here is my whole function and I am getting some weird results. It plays the last song in the list and skips over all others. Any explanation for maybe why? Again I am really not great with javascript, and help is MUCH appreciated!!
//play clicked track and those following
function play_clicked(api_type,clicked_key,song_count){
function showPlayTrack() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var outLink = xhr.responseText;
}
else {
var outLink = "There was a problem with the request" + xhr.status;
}
}
var vis = parent.document.getElementById("play_content");
vis.innerHTML = outLink;
setTimeout(300000);
}
for (var i=clicked_key;i<=song_count;i++){
if(window.track_id_array[i]){
if(api_type == "scloud"){
var soundcloud_id = window.track_id_array[i];
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.onreadystatechange = showPlayTrack;
xhr.open("GET", "getsoundcloud.php?streamurl="+soundcloud_id, true);
}
else {
alert("Sorry, but I could't create an XMLHttpRequest");
}
}else if (api_type == "youtube"){
var vid_id = window.track_id_array[i];
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}
else {
if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
}
}
}
if (xhr) {
xhr.onreadystatechange = showPlayTrack;
xhr.open("GET", "getyoutube.php?streamurl="+vid_id, true);
xhr.send(null);
}
else {
alert("Sorry, but I could't create an XMLHttpRequest");
}
}
}
}
}

Okay so I solved the problem by using recursive function calls. On click I call the play function, which reads the media id, checks the api type, increments the key and calls the ajax to get the iframe. The success function for the ajax then returns the iframe to the appropriate div, waits the length of the song and then calls the initial play function again with the incremented key as the param. Theres still some small things to work out, like adding or subtracting time if the user seeks in the media, but for the most part this is a great playlist solution!

Related

Visit a page using Javascript without leaving the current page

I have a Javascript file running on a page and I would like to log certain events as they occur. For example, I have a web store - and when people add an item to their cart, I want to log this event by visiting a page that I built:
function log_event(id) {
window.location.href = 'https://example.com/log/cart.php?id=' + id;
return false;
}
The log/cart.php page doesn't really have anything to display, all it does is insert a record into a database containing the item that was added to the cart, and the date.
The code that calls this function looks like:
document.getElementById('add-to-cart').addEventListener('click', function() {
// Add to the cart
...
// Track the item that was added
let id = document.getElementById('add-to-cart').getAttribute('data-id');
log_event(id);
});
With my current code, the log/cart.php actually replaces the current page. I want the opening of log/cart.php to only happen in the background without the user being interrupted. I don't want it to actually open a browser tab or window and let the user stay in the product page.
You can send an AJAX request to that endpoint:
function log_event(id) {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", 'https://example.com/log/cart.php?id=' + id, true);
xhttp.send();
return false;
}
fetch() can also be used, but be aware of its browser support (no IE).

Will an ajax call finish even after a page redirect?

I am trying to create a temporary image url for a local image and send it to Google to do a Search by Image. I don't want the image url to be permanent so I want to delete it right after I use it. I have the code below:
// Gets a URL that can be used to do a search by image through Google.
function getImageURL() {
var xml = new XMLHttpRequest();
xml.onreadystatechange = function () {
if (xml.readyState == 4 && xml.status == 200) {
deleteImageURL(); // asynchronous call to server to delete the URL
window.location.href =
"https://www.google.com/searchbyimage?site=search&sa=X&image_url="
+ xml.responseText; // the image url
}
}
xml.open("GET", "REST_ENDPOINT", true);
xml.send();
}
The function above calls the server, and when it finishes, will delete the url and redirect the page. The function "deleteImageURL()" is another ajax call done asynchronously. Currently, this loads the google page fine as the image URL is not done deleting the url by the time that the redirect happens.
My question is this: Will deleteImageURL() finish deleting the image URL even after the page redirects or will it stop (and thus, never delete the URL)?
EDIT: So I was thinking about what you guys were saying about race conditions and tried the following code instead:
// Gets a URL that can be used to do a search by image through Google.
function getImageURL() {
var xml = new XMLHttpRequest();
xml.onreadystatechange = function () {
if (xml.readyState == 4 && xml.status == 200) {
deleteImageURL(xml.responseText);
}
}
xml.open("GET", "REST_ENDPOINT"
+ id + "/public_url", true);
xml.send();
}
// Deletes the url for the image.
function deleteImageURL(imageURL) {
var xml = new XMLHttpRequest();
xml.open("GET", "REST_ENDPOINT_FOR_DELETE", true);
xml.send();
window.location.href =
"https://www.google.com/searchbyimage?site=search&sa=X&image_url="
+ imageURL;
}
This code works every time that I run it. I think that there still may be a race condition, but it seems to be working fine so far.
Thanks again.
The "deleteImageURL()" will finish deleting the image URL even after the page redirects..
Refer : Should I wait for ajax to complete to redirect a page?
The server won't stop processing the request (initiated by deleteImageUrl), but you will not be able to handle a callback if the current page unloads in the browser before the operation is completed.
If deleteImageURL(); contains an async call you should do the redirect when the call is completed. Your code will work when the call is synchronious. We don't see the source of deleteImageURL(); and can be more concrete, but you should do the same thing as you've done for getImageURL().

Efficient way to implement Likes features in a video application

I have a video based project.In this project I want to implement Likes features. That is there is a hyperlink on each video with the total like count and when user clicks on that hyperlink after then hyperlink is to be hidden and only show Liked text with total count of that video.
I have write this code in JavaScript with Ajax but main problem is that in one session if a user likes 5 videos then 5 times db will be hit. Is there any efficient way to implement it?
<div id="status${video.id}"> Like- </div><a id="like1${video.id}" style="color:#ffffff;">${video.likesCount}</a>
function callLike(id)
{
document.getElementById("like"+id).innerHTML='300';
var postData = '?Id='+id;
var url =protocol+'//'+host+'/xxx/getLike'+postData;
// alert("url:"+url);
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.onreadystatechange = likesres;
req.open("POST", url, true);
req.send(null);
}
function likesres()
{
if (req.readyState == 4) {
if (req.status == 200) {
response = req.responseText;
document.getElementById("like1"+id).innerHTML=response;
document.getElementById("status"+id).innerHTML='Liked--';
}
}
}
You need a better project architecture if you want to make this project scalable.
A starting point of what you should do is implementing an in-memory queue on your server-side code and a processing mechanism for it. Every time a user likes a video, this information is added to the queue and every 2 minutes, the queue is processed and all its content gets written to the database.
This way, you can control how many times the DB will be hit.
However, it might add some delay for the users if you set the processing time too infrequent.
Hope this helps and gives you an idea to what needs to be done.

JW Player do action based on elapsed time

I have a video and series of comments on the video. Each comment has a specific time associated with the video. For example video 1 has 3 comments. one in second 15, another in second 30, and the last comment is in second 45.
I can show all the comments. However, instead I want each comment to be shown on its associated time of the video. For example, comment 1 should only be appeared in second 15 and lasts until second 30 where it is replaced by second comment and so on.
I'm using JW Player to play the video and can get getPosition() function to get the current elapsed time of the video. It should be a simple JavaScript code to achieve this but unfortunately I'm so beginner with JS.
My own idea to achieve this is to use onTime function and for each position check if there is a comment in the server or not, and retrieve if there is. As in:
<script>
jwplayer("container1").onTime(
function(event) {
{
var comment = get_comment_of(event.position);
setText(comment);
function setText(text) {
document.getElementById("message").innerHTML = text;
}
});
</script>
However, this is an expensive function and will send huge number of requests to the server.
Ok, the best solution I have preloaded the comments in a javascript array when the page is loaded, then show them when they occur using onTime function. This way there is no need to send a new request on on every onTime frame. As the comments are already available on the client side
var timeArray = <?php echo json_encode($timeArray) ?>;
var commentArray = <?php echo json_encode($commentArray) ?>;
jwplayer("container1").onTime(
function(event) {
for (var i = 0; i < timeArray.length; i++)
{
var time = timeArray[i]
var comment = commentArray[i];
if (event.position >= time) {
setText(comment);
}
}
function setText(text) {
document.getElementById("message").innerHTML = text; }
}
);

execute onChange when a certain condition/event is detected jQuery

alright.. i have an input box that captures paste event and checks if the pasted text/string is a youtube url. if yes, it will forward data to some PHP to process..
the result json data is being displayed here $('.printdata').append(response);
concerns:
what i didn't have in my code, is to recognize if the whole text or
the youtube link is removed/cut/deleted. it should also remove the
displayed data.
accept the first youtube URL, if multiple youtube URL is found, send the first link to PHP, then ignore the others, just display it as text.
my workaround
what im thinking (tho not sure) is to put some onchange() event
somewhere to recognize $("$input") element is being changed.
accept only a single paste event and ignore if paste() is repeated. -not sure if this is the right approach.
http://jsfiddle.net/8Pvr4/4/
to test what im trying to explain, input any youtube url in the textfield, and it should display something.
then remove the url, the data remains. OR add another URL consecutively. the resulting data will stack.
$(document).ready(function() {
//some regex
$("#input").bind('paste', function(e) {
var val = undefined;
//get pasted data
if(window.clipboardData && window.clipboardData.getData) {
val = window.clipboardData.getData('Text');
} else if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData){
val = e.originalEvent.clipboardData.getData('text/plain');
}
//check for youtube URL
if (youtube.test(val)) {
var yurl = val.match(youtube)[0];
$.post("youtubejson.php?url="+ yurl, {
}, function(response){
$('.printdata').append(response);
});
}
});
I'm not sure i understand your question properly, but i guess your result is stacking and not getting replaced, you can use .html(response) instead of .append(response) to stop stacking.

Categories