Dealing with facebook Graph API objects in javascript - javascript

I am trying to access specific albums via their location from a Facebook page via a graph API call and ultimately display them on a webpage.
Essentially I think I need to loop through the object that Facebook sends back (response in this case) and only store objects which contain the substring "Germany" in the location description to the variable albums. Currently nothing happens in the console when I trigger the method.
I'm kind of stuck at this point, I can make API calls and have them returned from the specific page via other functions, so my permission seems to be fine, I'm just structuring this function incorrectly (I think, I'm relatively new to JS and Jquery).
model.getPhoto = (function(data){
var albums;
FB.api(
'/--USER ID GOES HERE--/albums',
'GET',
{"fields":"link,location"},
function(response){
for (var i=0; i<response.length; i++){
if (response.albums.location[i] = "Germany"){
albums = response.albums.location[i];
i++;
}
console.log(albums);
}
}
);
});

You are setting model.getPhoto as a new function. If your code is complete, you never call this function. I added some lines then you can try to fix and see some results... Also changed some lines, created albums as an Array and put i++ outside of if to execute for loop correctly.
Last line calls your function.
model.getPhoto = (function(data){
FB.api('/--USER ID GOES HERE--/albums',
'GET',
{"fields":"link,location"},
function(response){
var albums = new Array();
for (var i=0; i<response.length; i++){
if (response.albums.location[i] == "Germany"){
albums.push(response.albums.location[i]);
}
i++;
console.log(albums);
}
});
});
model.getPhoto({var1: "value1"});
I suggest you play more with javascript and logics, take a look inside some libraries like jQuery itself, as you are not using it here, just pure JS, and have fun!
EDIT
When comparing, you must use == instead of =
Best,
Eder

Related

Function getting informations from website

Lets take a look here: http://www.pepco.pl/sklepy
When you click one particular shop, there appears window with opening hours and address. In site source I can see that there is javascript function. Is it possible to get all those data using javascript function without having to click on every shop? I need this for informational purposes.
When you click on a shop, there s a Ajax call which request the specific informations.
Try to use this url for your purposes.
var count = 244,
$output = $('#output');
for (var i = 0; i < count; i++) {
$.ajax({
url: 'http://www.pepco.pl/web/ajax/sites.city.php?param='+i+'&date_format=Y-m-d',
})
.done(function(data) {
$output.append($("<div class='item'>"+data+"</div>"));
})
.fail(function() {
$output.append($("<div class='item'>error</div>"));
});
}
Because of crossdomain policy you cant use this from any other page. A curl solution could work

Arrays disappear outside of JSON request

I am attempting to set up an array with the various properties of a YouTube video (you may be thinking this is somewhat superfluous, however I am planning on adding other sources in the future). I am able to add these values into the array within the JSON request, but once I get out of it, they just disappear. Any ideas?
var socialPosts = new Array();
$.getJSON('https://gdata.youtube.com/feeds/api/videos?author=google&max-results=5&v=2&alt=jsonc&orderby=published', function(data) {
for(var i=0; i<data.data.items.length; i++) { //for each YouTube video in the request
socialPosts[i]={date:Date.parse(data.data.items[i].uploaded), title:data.data.items[i].title,source:"YouTube", thumbnail:data.data.items[i].thumbnail.hqDefault, url:'http://www.youtube.com/watch?v=' + data.data.items[i].id}; //Add values of YouTube video to array
}
console.log(socialPosts[0].date); //This returns the correct data
});
console.log(socialPosts[0].date); //This returns with undefined
You are trying to access results of Ajax asyn call which are not yet returned. You need to use result in call back function or pass the results to some function.
var socialPosts = new Array();
$.getJSON('https://gdata.youtube.com/feeds/api/videos?author=google&max-results=5&v=2&alt=jsonc&orderby=published', function(data) {
for(var i=0; i<data.data.items.length; i++) { //for each YouTube video in the request
socialPosts[i]={date:Date.parse(data.data.items[i].uploaded), title:data.data.items[i].title,source:"YouTube", thumbnail:data.data.items[i].thumbnail.hqDefault, url:'http://www.youtube.com/watch?v=' + data.data.items[i].id}; //Add values of YouTube video to array
}
console.log(socialPosts[0].date); //This returns the correct data
somefun(socialPosts[0].date);
});
Because that is an Ajax function and it happens async meaning the code outside the closure executes before the call is finished

Dynamic listeners based on array

I'm playing with mobile app creation with jQuery and an api I built using Slim.
My overall goal is to create a list of buttons that when clicked will call a function with the appropriate parameters.
I am successfully sending my request to slim, getting a list of users and storing the results in a global array of User objects.
Next I am iterating through the array appending html to the document to show the buttons. At the same time I am adding a click listener. The listener gets added, but not like I expect.
Users is an array of user objects with global scope. A user object can be boiled down to [{"name":"User's name"}].
Also relevant might be the fact that I'm doing this in a call back.
$.getJSON(url, function(data){
for(i=0;i<data.length;i++)
{
var u = new User();
u.name = data[i]['name'];
}
})
//The success handler DOES get called.
.success(function() {
for(var i=0; i<users.length; i++)
{
//this part works. users[i] is accessed as expected.
var html_string = '<li>'+users[i].name+'</li>';
$("#myUL").append(html_string);
$("#myUL li:last").click(function(){
//logs undefined
console.log(users[i].name);
//Handle the event
eventHandleFunction()
});
}
})
I'm well enough versed in programming in general to know that what I'm doing does not fall into best practices, but I am so illiterate in javascript that I don't know the right way to fix it. In addition to the howto answer I'd really appreciate anyone who took some time to point me to useful resources.
Update: After reading an answer about using delegate to assign handlers I have updated my code a bit. Now it looks like this. Note: I've only not updated the code above in order to get an answer to the 'why' part of the original question.
$("#myUL").delegate("li","click",function(){
//sets the attribute name of the global var user
user.name = $(this).text();
//lets see what user.name is now. Oh, look. It's what i expect
alert(user.name);
//do whatever else i want to do here.
});
//This json request is now (i believe) entirely unnecessary to answer the question.
$.getJSON(url, function(data){
for(i=0;i<data.length;i++)
{
var u = new User();
u.name = data[i]['name'];
}
})
//The success handler DOES get called.
.success(function() {
//No longer relevant
})
you can use delegate
$("#myUL").delegate("li:last","click",function(){
//event handler code here
});
this way you dont have to explicitly attach click event handler to every dynamically added li in the DOM
if you are using jquery version 1.7+ then you can use .on method like
$("#myUL").on("click","li:last",function(){
//event handler code here
});
the why part
the reason i see is the scope
for(var i=0; i<users.length; i++)
{
var html_string = '<li>'+users[i].name+'</li>';
$("#myUL").append(html_string);
$("#myUL li:last").click(function(){
//logs undefined BECAUSE i is undefined inside the click handler
console.log(users[i].name);
//Handle the event
eventHandleFunction()
});
}
for(var i=0; i<users.length; i++) {
var numb = i,
html_string = '<li>'+users[numb].name+'</li>';
$("#myUL").append(html_string);
$("#myUL li:last").click(function(){
console.log(users[numb].name);
eventHandleFunction()
});
}

Ajax HEAD request via Javascript/jQuery

I seem to be having some issues with making HEAD requests, and preserving the integrity of data in an array.
Given this snippet:
var imageTemp = Array();
$('*')
.each(function(index){
if($(this).css('background-image') != 'none'){
imageTemp.push($(this).css('background-image').slice(5, -2));
}
});
I capture the URLs of all background-images on a given page. Now, trying to grab the size of each image via HEAD requests for Content-Length, I use this snippet:
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
ajaxSizeRequest = $.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
success: function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
});
}
However, when I dump imageData via console.log, I each element (which should be an array containing the URL and the content-length) ends up as [undefined, XXXX] where XXXX is always the size of the last requested Content-Length
I'm stumped, though it appears to be a timing/scoping issue. Do I have a sort of race-condition occuring here?
The problem is that the single variables i and ajaxSizeRequest being captured by the callback function are the same variables for all instances of the callback function. I think if you call a function and pass the index variable to it and, at the same time, scope the request variable locally to the function itself use the response parameter of the done handler, you should end up with independent variables captured by the callback. It should then reference each array element and each response variable correctly.
var imageData = Array();
for(var i = 0; i < imageTemp.length; i++){
updateImageData( i );
}
function updateImageData( i )
$.ajax({
type: "HEAD",
async: true,
url: imageTemp[i],
}).done(function(message,text,jqXHR){
imageData.push([imageTemp[i], jqXHR.getResponseHeader('Content-Length')]);
});
}
looks like your i isnt properly closed-in
in addition, you can't use ajaxSizeRequest because it too is pointing to just one request (probably the last, because the loop will execute very fast)
just wrap your success callback function as follows, changing the reference to ajaxSizeRequest:
success: (function(i){
return function(data,status,xhr){
imageData.push([imageTemp[i], xhr.getResponseHeader('Content-Length')]);
};
})(i)
You can scope I like so:
success: function(i){
return function(message){
imageData.push([imageTemp[i], ajaxSizeRequest.getResponseHeader('Content-Length')]);
}
}(i)
You have a single i variable which is shared by all of the callbacks.
Since AJAX is asynchronous, all of the callbacks run after your loop is finished, and they all get the same i.
To fix this, you need to move the AJAX call into a separate function that takes i as a parameter.
Thus, each callback will get a separate i parameter.
If anyone still having trouble with this, and since this post is, like, 5 years-old already, here's a more 'modern' version of the answer: just use let instead of var in the original post's for loop.
Info: Is there any reason to use the “var” keyword in ES6?
and: MDN - Let syntax

Javascript callback function issue

Background
I'm writing an asynchronous comment system for my website, after reading plenty of tutorials on how to accomplish this I started building one from scratch. The comments are pulled using a JSON request and displayed using Javascript (jQuery). When the user adds a new comment it goes through the hoops and finally is sent via AJAX to the backend where it's added to the database. In the success section of the AJAX request I had the script empty the comments, then repull the new list (including the new post) and redisplay them.
Problem
While that was all nice, since it's making the page much shorter, then much longer it messes up where the user is viewing the page. I wanted to have it readjust the page back down to the end of the comment list (where the add comment form is). It also re-enables the add button, which was disabled when the clicked it to prevent impatient people from spamming.
$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
While this worked all well and good in theory, it seemed that the browser was getting ahead of itself and processing the window.location before the getComments function was done. So I read a little more and googled it and it seemed people were saying (for similar problems) to use callback functions, so I came up with this:
$('#commentList').empty();
getComments('blog', $('input#blogId').val(), function() {
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
});
This generates no javascript errors according to FireFox, but nothing within the callback function is working, it's not re-enabling the button nor changing the window.location.
Any ideas? Better ways to go about it? Do I have a glaring typo that I can't seem to see?
Thanks!
Update
I was under the impression the callback functions were a standard thing you could use.
function getComments(type, id)
{
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++)
{
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" )
{
legend.text((x+1) + ' - ' + data[x].name);
}
else
{
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
}
});
}
This is called on document ready. Pulling all the comments and displaying them inside the #commentList div. When the user submits his/her comment it performs an AJAX request to a PHP script that adds the new comment to the database, upon success of this I have this:
$('#commentList').empty();
getComments('blog', $('input#blogId').val());
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
Deletes all the comments from the page.
Uses JSON to request the comments again (including the users new one).
Moves the page to the #addComment anchor, which is where their new comment would be displayed.
Re-enables the add comment button.
The problem is that the browser does the window.location line before the getComments function is done rendering all the comments, so as the page grows the user isn't looking anywhere near their new comment.
I expect here the problem is your getComments() function (for which more detail is required). You're supplying a third argument being a callback but does the function actually use a callback? What is it doing?
Certain jQuery functions provide callbacks but this isn't an automatic feature. If you're waiting for a user to type a comment you need to trigger the relevant event when they click "Done" or whatever they do.
Ok, try this:
function get_comments(type, id, callback) {
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++) {
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" ) {
legend.text((x+1) + ' - ' + data[x].name);
} else {
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
if (typeof callback != 'undefined') {
callback();
}
}
});
}
Note: the difference here is that a third argument is supplied to get_comments() which is a callback that'll be called at the end of your $.getJSON() callback. That'll give you the proper ordering you want.
I might also suggest not constructing the HTML like that but including it in your page and hiding/unhiding it as necessary. It tends to be much more performant that dynamic HTML and have less issues (eg new HTML, unless you use $().live() will not have relevant event handlers).
Edit: Made the callback optional as per the comments. With the above code you can call the function without or without the callback.
Simple. Re-enable the button and go to the anchor after you receive the request and process the information. Like so:
function getComments(type, id)
{
// ADDED
$('#commentList').empty();
$.getJSON("/ajax/"+type+"/comments?jsoncallback=&id="+id, function(data) {
for (var x = 0; x < data.length; x++)
{
var div = $("<div>").addClass("comment").appendTo("#commentList");
var fieldset = $("<fieldset>");
var legend = $("<legend>").addClass("commentHeader");
if ( data[x].url == "" )
{
legend.text((x+1) + ' - ' + data[x].name);
}
else
{
$("<a>").attr({href: data[x].url}).text((x+1) + ' - ' + data[x].name).appendTo(legend);
}
legend.appendTo(fieldset);
$("<div>").addClass("date").text(data[x].timestamp).appendTo(fieldset);
$("<p>").addClass("comment").text(data[x].content).appendTo(fieldset);
fieldset.appendTo(div);
}
// ADDED
window.location = "#addComment";
$('#comAdd').removeAttr('disabled');
});
}
Personal opinion: rather than fetching all comments, why not fetch comments from a certain date? When you load the page, include a server time in the response. The Javascript uses this to query behind the scenes (to automatically check for new comments). The JSON response includes a new server time, which is used in the next response.
How would you handle deleted comments? Easy: have a deleted_on column in your database table, query it, and spit that out in the JSON response along with new posts.
Suggestion: instead of #addcomment, ID comments by timestamp.

Categories

Resources