jquery $(data).each doesn't work with promises? - javascript

I have an each() loop in my AJAX handler to do push into my temp array, but in the end I still get an empty array. It's strange, I remember I once use promise on each() so it has no problem.
var temp = [];
$.ajax({
type: 'GET',
url: '/endpoint',
success: function(data) {
$(data).each(function() {
//do some stuff
console.log(something); // working
temp.push(something);
}).promise().done(function() {
console.log(temp); // still empty array?!
});
});
update: here's how people has done it https://stackoverflow.com/a/8941358/7095330

Reducing your script to what your question is asking, everything seems to be working fine. Hopefully this will help you find out that your problem is somewhere else in your code:
var temp = [];
var data = [1,2,3,4,5,6,7,8];
$(data)
.each(function(thing) {
//do some stuff
console.log(thing); // working
temp.push(thing);
})
.promise()
.done(function() {
console.log(temp); // still empty array?!
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
However the promise().done() is pretty weird; I can't see why you'd need that there.
Sounds like a case for map, where you have an input array and you want to transform its contents.
var data = [1,2,3,4,5,6,7,8]
var changedData = data.map(function (datum) {
// do stuff
return 'did stuff to ' + datum;
});
console.log(changedData)
Unless what you were trying to do was the following, which still works. PEBKAC error perhaps?
var temp = [];
$.ajax({
type: 'GET',
url: 'https://google.com/',
// replaced success: with error:, for example's sake
error: function(data) {
$(data).each(function() {
//do some stuff
console.log('something');
temp.push('something');
}).promise().done(function () {
console.log('each done', temp);
});
},
done: function() {
console.log('ajax done:', temp);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

You forgot a bracket }
var temp = [];
$.ajax({
type: 'GET',
url: '',
success: function(data) {
$(data).each(function() {
//do some stuff
console.log('something'); // working
temp.push('something');
}).promise().done(function() {
console.log(temp); // still empty array?!
});
}});
see https://jsfiddle.net/gw10un58/

Related

why am I getting undefined at the moment when I click my button?

I want to try to display my notification json through ajax, but however when I try first show me undefined, and then show me my json what am I doing wrong?
$(function (doc, win, $) {
var notification = win.Notification || win.mozNotification || win.webkitNotification;
var $badge = $("#notifications-badge");
var $list = $("#notifications-list");
var $button = $("#notifications-button");
URL_GET_NOTIFICATION = BASE_URL + 'notifications/getNotification';
function check_notifications() {
$.ajax({
type: 'GET',
url: URL_GET_NOTIFICATION,
//data: { timestamp : timestamp },
dataType: 'json',
async: true,
success: function (data) {
console.log(data);
}
});
}
$button.click(function (e) {
alert(check_notifications());
});
}(document, window, jQuery));
All functions return undefined by default when called, unless something else is specified.
You'd get the same with just
function go() {};
alert( go() ); // undefined
And that's basically what you're doing, alerting a function that doesn't return anything.
If you return something from the function, it works
function go() { return 'Hello Kitty' };
alert( go() ); // Hello Kitty
But, as you're using ajax inside the function, you can't really return the result from that, as it's asynchronous and executes some time after the result is returned.
You'd have to use a callback or promise to make it work.
function check_notifications() {
return $.ajax({
type: 'GET',
url: URL_GET_NOTIFICATION,
//data: { timestamp : timestamp },
dataType: 'json'
});
}
$button.click(function (e) {
check_notifications().done(function(data) {
alert(data);
});
});
As a sidenote, use the console when debugging, not alerts.

Only append new data

I'm trying to make a log parser, that updates the log every 10 seconds. It's mostly functional, but when I try to update it, it just appends the whole log again, instead of just the new data.
My Javascript:
$(document).ready(function() {
var data;
var lines;
$.ajax({
async: false,
type: 'GET',
url: 'test.log',
success: function(log) {\
data = log;
lines = data.split("\n");
console.log("Received log");
}
});
function updateLog()
{
$.ajax({
async: false,
type: 'GET',
url: 'test.log',
success: function(log) {
data = log.replace(data, "");
lines = log.split("\n");
console.log("Received log");
}
});
$.each(lines, function(n, elem)
{
$('#text').append('<div>' + elem + '</div>');
});
}
$.each(lines, function(n, elem)
{
$('#text').append('<div>' + elem + '</div>');
});
setInterval(function(){updateLog();}, 10000);
});
Example test.log content:
Hello
How are you?
But instead of it only adding potential new lines, it just copies the whole thing even though I think it shouldn't happen because of the replace, which is supposed to take the old data and change it into '' in the new data (only leaving new lines).
It looks to me like you save only the new part of last request to data, so you are actually only replacing the part of the log that was new the last time you updated the log by an empty string. Moreover, you are not using data but log (which is the full log) to compute lines, and are appending all the lines in lines to your div.
I think something like this should work:
$(document).ready(function() {
var processed_data = '';
function updateLog() {
$.ajax({
async: false,
type: 'GET',
url: 'test.log',
success: function(log) {
var new_data = log.replace(processed_data, '');
processed_data = log;
console.log("Received log");
var lines = new_data.split('\n');
$.each(lines, function(n, elem) {
$('#text').append('<div>' + elem + '</div>');
});
}
});
}
updateLog();
setInterval(function(){updateLog();}, 10000);
});
Note that I also got rid of some of the code duplication that was in your example by just calling updateLog() on load instead of copying its contents.
It would also probably be more efficient to just keep track of the length of the part of the log that is already printed. Something like this:
$(document).ready(function() {
var processed_data_length = 0;
function updateLog() {
$.ajax({
async: false,
type: 'GET',
url: 'test.log',
success: function(log) {
var new_data = log.substring(processed_data_length, log.length);
processed_data_length = log.length;
console.log("Received log");
$.each(lines, function(n, elem) {
$('#text').append('<div>' + elem + '</div>');
});
}
});
}
updateLog();
setInterval(function(){updateLog();}, 10000);
});
Strings are immutable, so the log variable isn't updated by the .replace() call. Your ajax should probably look like:
$.ajax({
async: false,
type: 'GET',
url: 'test.log',
success: function(log) {
data = log.replace(data, "");
lines = data.split("\n");
console.log("Received log");
}
});

Passing json result to another ajax

This is the continue from this : Link
My storyboard is like this. I want to autorefresh my page. Coz I create a live monitoring to manage requests from my users. When a new comment is create from user, I wanna create a notification.
So, I choose use js/jquery.
I try so hard to implement that to my ajax response like this
/* This is function to initialized old comment as return a first */
function initializedFirstComment(handleData) {
$.ajax({
url: "<?php echo base_url() . 'control_closing/getKomentarMD/' ?>",
type: 'POST',
dataType: 'json',
success: function(data) {
handleData(data);
}
});
}
For the second array is like this :
/*For the second array */
function refreshByManager(first) {
var audioElement = document.getElementById('notif-md');
audioElement.addEventListener('ended', function() {
this.currentTime = 0;
this.play();
}, false);
setTimeout(function() {
$.ajax({
url: '<?php echo base_url() . 'control_closing/getKomentarMD/' ?>',
type: 'POST',
dataType: 'json',
success: function(second) {
console.log(first); // For debug first array, and in firebug it success.
console.log(second);// For debug second array, and in firebug it success.
var difference = function(list1, list2, id, attr) {
var map = {};
// Create map.
list1.forEach(function(item) {
map[item[id]] = item;
});
// Find diff.
return list2.filter(function(item) {
var target = map[item[id]];
// Return if the item is not exist in first, or the target attr is different.
return (typeof target === 'undefined' || item[attr] !== target[attr]);
});
}
var diffs = difference(first, second, 'id_request', 'comment_bapak');
console.log(diffs);
alert(diffs[0].comment_bapak);
refreshByManager();
}
});
}, 5000);
}
So, in main document will be like this.
$(document).ready(function() {
initializedFirstComment(function(output) {
refreshByManager(output); // Check it
})
}
I dont understand, why the output is like this :
The result of debug :
console.log(diffs);
alert(diffs[0].comment_bapak); is =>
[]
TypeError: diffs[0] is undefined
I am so desperate. Any help it so appreciated.
Well, I tested the code a bit and the difference function returns an empty list if the list2 doesn't contain objects that differ from the objects of the list1.
So I would check the diffs variable first, before trying to access it.
var diffs = difference(first, second, 'id_request', 'comment_bapak');
if (diffs) {
console.log(diffs);
alert(diffs[0].comment_babak);
}
Another problem I noticed is that you're defining the difference function over and over again in the success callback function. You should move it outside from there.

Return values from an Ajax function

I am trying to create a block of text that will update itself when the text changes from a Json string.
Basically I started with:
function streamSong(index) {
if (!isUndefined(myPlaylist[index].title))
return myPlaylist[index].title;
else return '';
}
then modified it to look like this:
function streamSong(index) {
var currentSongName = 'here';
if (!isUndefined(myPlaylist[index].title)) {
var intervalFunc = function(){
var jsonData = null;
$.ajax({
url: 'http://www.thesite.com/pullJson.php?stream=rapstation',
dataType: "json",
data: { get_param: 'employees' },
success: function (data) {
currentSongName = 'now here';
},
error: function (data) {
currentSongName = 'not working';
}
});
};
setInterval (intervalFunc, 60000);
setTimeout (intervalFunc, 1);
return currentSongName;
}
else return 'no title';
}
The first function fired off fine and returned my Stream Title.
The second function fires off, but I never am able to modify the value of currentSongName.
I am still a bit new to Javascript and ajax so excuse my ignorance, but I obviously want to ultimately set the value of currentSongName to the Json value I retrieve, but for now I would just like it to be able to change values on a timer.
Am I going about this all wrong?
The variable is modified just fine, but too late. The AJAX call is asynchronous, so the variable is used to return the value before the value is assigned to it.
You would use a callback to handle the result. With the original code it would look like this:
function streamSong(index, callback) {
if (!isUndefined(myPlaylist[index].title)) {
callback(myPlaylist[index].title);
} else {
callback('');
}
}
Usage:
streamSong(42, function(title) {
// do what you want with the title
});
For the AJAX call the callback would be used like this:
function streamSong(index, callback) {
var currentSongName = 'here';
if (!isUndefined(myPlaylist[index].title)) {
var intervalFunc = function(){
var jsonData = null;
$.ajax({
url: 'http://www.thesite.com/pullJson.php?stream=rapstation',
dataType: "json",
data: { get_param: 'employees' },
success: function (data) {
callback('now here');
},
error: function (data) {
callback('not working');
}
});
};
setInterval (intervalFunc, 60000);
setTimeout (intervalFunc, 1);
} else {
callback('no title');
}
}

JQuery reverse each() with find()

I know this kind of question has been asked before, but the general solution of
$($("input").get().reverse()).each(function() { /* ... */ });
is not working for me. I have an xml document that contains a list of concerts that I'd like to display on a webpage. So, in JQuery:
$.ajax({
type: "GET",
url: "concerts.xml",
dataType: "xml",
cache: false,
success: function(xml) {
$(xml).find('concert').each(function() {
/*do stuff*/
});
}
});
However, I'd like to display the concerts in reverse order. So, I tried the following, but it did not work:
$.ajax({
type: "GET",
url: "concerts.xml",
dataType: "xml",
cache: false,
success: function(xml) {
$($(xml).find('concert').reverse()).each(function() {
/*do stuff*/
});
}
});
Any assistance would be much appreciated. Thanks.
You excluded the call to the get()[docs] method.
// --------------------v
$($(xml).find('concert').get().reverse()).each(function() {
This is needed to get an Array of the elements from the jQuery object. This is what allows you to call .reverse(), which is on Array.prototype.
To walk through the items in reverse order, why not just use code like this:
var data = $("input");
for (var i = data.length - 1; i >= 0; i--) {
var item = data[i];
// do whatever you want to do with item here
}
Or, if you want to make a function out of it that takes a jQuery object and your function:
function reverseEach(jQueryObj, fn) {
for (var i = jQueryObj.length - 1; i >= 0; i--) {
if (fn.call(jQueryObj[i], i, jQueryObj[i]) === false) {
break;
}
}
}
So, you could then call:
reverseEach($(xml).find('concert'), function() {
// do stuff here
});
or:
reverseEach($("input"), function() {
// do stuff here
});
Or, you could even make reverseEach a jQuery plugin if you wanted.

Categories