FullCalendar and Multiple Dynamic Event Sources - javascript

I have FullCalendar (1.6.4) working with a single JSON feed (a single user's calendar). Now, I want to enhance the functionality so the calendar will display multiple user calendars (the admin and their child account calendars). Until the calendar is called, I won't know how many user calendars will be called. So, I have a Ajax function call a PHP script that returns a JSON feed of all user ID's for the admin account.
$(document).ready(getUsers);
function getUsers() {
var data = $.ajax( {
url: '/s/calendar_userdata.php',
method: 'GET',
dataType: 'json',
success: function(userData) {
var user_count = userData.length;
var uid_array = [];
// Create the sources
for (var i = 0; i < user_count; i++)
{
var uid = userData[i].uid;
if(!uid_array[i]) uid_array[i] = [];
uid_array[i] = uid;
}
}
});
loadCal();
}
The Ajax call works. I get an array (uid_array) such as [7,47] back, as expected. I would like to use this array within my loadCal function as illustrated below, but I can't get it to persist after the getUsers function has concluded.
function loadCal() {
$('#calendar').fullCalendar({
eventSources: [
{
url: '/s/events.php',
type: 'GET',
data:
{
uid: uid_array
}
}
],
editable: true,
.........
I've tried:
1) Creating a global variable by initially defining uid_array outside of getUsers without the "var".
2) Setting "window.uid_array = uid_array;" within the getUsers function.
3) Adding "return uid_array;" at the end of the getUsers function.
4) Adding a closure at the end of the getUsers function. But, I don't grasp them well enough to believe I did it correctly.
I have 2 questions:
1) How do I make the array (uid_array) available outside of getUsers?
2) In what format does the array need to be so that fullCalendar will recognize and use it?
I've been stuck on this for a while. Thanks much.

I think if you change the location of loadCal function you can accomplish your objective:
function getUsers() {
var data = $.ajax( {
url: '/s/calendar_userdata.php',
method: 'GET',
dataType: 'json',
success: function(userData) {
var user_count = userData.length;
var uid_array = [];
// Create the sources
for (var i = 0; i < user_count; i++)
{
var uid = userData[i].uid;
if(!uid_array[i]) uid_array[i] = [];
uid_array[i] = uid;
}
//CALL loadCal FROM HERE
loadCal(uid_array);
}
});
}
Modify loadCal to accept array of uids:
function loadCal(uidArray) {
$('#calendar').fullCalendar({
eventSources: [
{
url: '/s/events.php',
type: 'GET',
data:
{
uid: uidArray
}
}
],
editable: true,
When you are making ajax call in getUsers it is not returned and loadCal is called. So you need to make sure that it is called only after ajax is returned that is in success callback.

Related

JavaScript is not catching the correct list item from JQuery-AJAX [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 2 years ago.
I have two functions main function which JQuery , and the other one in Javascript.
jQuery :
$(document).ready(function () {
$('#ProvisionLink').click(function () {
var queryTargetList = [ "Item1","Item2","Item3","Item4"]
var data = ["Data1","Data2","Data3","Data4" ]
event.preventDefault();
var i;
for(i = 0; i < queryTargetList.length; ++i) {
var dataItem = data[i];
var QueryItems = queryTargetList[i];
console.log("Before Launching the Javascript : " +QueryItems)
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
type: 'POST',
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});
}
});
});
Java script :
function getInventory(data,queryTarget){
console.log("In Get Inventory Function in javascript ... " +queryTarget)
var queryTarget = "#"+queryTarget
// get the query id
const SelectBoxQuery = document.querySelector(queryTarget)
console.log(SelectBoxQuery)
// resetting the values to enter all the new one.
SelectBoxQuery.options.length = 0; // reset the values
// making a loop to reach each element item in the list
for (var i = 0; i < data.length; ++i) {
// add new element which is option to the targeted ID
var SelectBoxQuery_Addition = document.createElement('option');
// adding a text to that option
SelectBoxQuery_Addition.text = data[i];
// apply the adding .
SelectBoxQuery.add(SelectBoxQuery_Addition)
}}
The problem is, after i get response from python FLASK to Jquery function. in success part it should launch the javascript function with the same i of the queryTargetList.
for example if i pass data[1], i expect to have queryTargetList[1] also.
but in javascript console.log function. that does not happen. it printing the last item of the queryTargetList list.
Print:
Before Launching the Javascript : Item1
JQueryTests.js:11 Before Launching the Javascript : Item2
JQueryTests.js:11 Before Launching the Javascript : Item3
JQueryTests.js:11 Before Launching the Javascript : Item4
operationJavaScript.js:115 In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
I do not know what am doing wrong :(
Since the ajax call is an async operation, the loop variable i would have changed by the time the success method gets called. There is no guarantee that the i would have reached the end.
You would need to wrap the variables, in a closure so that it success methods gets the correct item.
Sample code not tested.
$(document).ready(function () {
$('#ProvisionLink').click(function () {
var queryTargetList = [ "Item1","Item2","Item3","Item4"]
var data = ["Data1","Data2","Data3","Data4" ]
event.preventDefault();
var i;
for(i = 0; i < queryTargetList.length; ++i) {
var dataItem = data[i];
var QueryItems = queryTargetList[i];
console.log("Before Launching the Javascript : " +QueryItems)
(data,queryItem)=>{
$.ajax({
url: '/operation',
data: {DataType: data,},
type: 'POST',
success: function (response){ getInventory(response,queryItem) },
error: function (error) {console.log(error);}
});
})(dataItem,QueryItems);
}
});
});
set the async option to false:
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
async: false,
type: 'POST',
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});
Another way: send queryTargetList[i] value to server and response get from server..
You must consider the issue of synchronization and non-synchronization, because you did not set the async attribute, so the default will be true. The easiest way is to set the async attribute to false
Like my example below, for detailed usage, you can refer to here
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
type: 'POST',
async: false,
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});

ajax call is failing when called in a function inside a for loop

I am trying to call an API and get and display all orders and then for each order to call another endpoint which returns the details about the worker who has placed the order and display these details along with the order details.
Using Ajax, I call the first endpoint which returns all the order. I looped through all returned orders and display the details about each order. Inside the loop I call a function which take as parameter the WorkerId (getWorker(WorkerId). This function is created outside the for loop and contains another ajax call to the second API endpoint, which returns the details about the worker.
var app = {}; // creating a empty object to hold the data
// getAllOrders method will make the Ajax request to the API
app.getAllOrders = function() {
$.ajax({
url: 'https://www.hatchways.io/api/assessment/work_orders',
method: 'GET',
dataType: 'json',
data: {
format: 'json'
},
success: function(result) {
console.log('Ajax is working.');
app.displayAllOrders(result);
},
error: function(error) {
console.log('Something went wrong.');
console.log(error);
}
});
}; //end app.getAllOrders function
app.getAllOrders();
app.displayAllOrders = function(allOrders) {
console.log(allOrders);
// getWorker method will make the Ajax request to the API
app.getWorker = function(id) {
console.log('Ajax is working.');
$.ajax({
url: 'https://www.hatchways.io/api/assessment/workers/' + id,
method: 'GET',
dataType: 'json',
data: {
format: 'json'
},
success: function(result) {
console.log('Ajax is working.');
app.workersInfo(result);
},
error: function(error) {
console.log('Something went wrong.');
console.log(error);
}
});
}; //end app.getWorker function
// creating a method to inject our data into the DOM
app.workersInfo = function(worker) {
console.log(worker);
// Creating var for each piece of data for worker id
var comp = $('<p>').text(worker.worker.companyName);
var nameWorker = $('<p>').text(worker.worker.name);
var email = $('<p>').text(worker.worker.email);
var workerId = $('<p>').text(worker.worker.id);
var workerInfo = $('<div>').append(nameWorker, comp, email, workerId);
$('#allOrders').append(workerInfo);
}; //end app.workersInfo function
for (var i = 0; i < allOrders.orders.length; i++) {
// creating var for each piece of data for order
var id = $('<p>').text(allOrders.orders[i].id);
var nameOrder = $('<h3>').text(allOrders.orders[i].name);
var desc = $('<p>').text(allOrders.orders[i].description);
var deadline = $('<p>').text(allOrders.orders[i].deadline);
var workerId = $('<p>').text(allOrders.orders[i].workerId);
// appending in div all info for the order
var orderInfo = $('<div>').addClass('orderInfo').append(nameOrder, id, desc, deadline, workerId);
// appending in div all info for worker
$('#allOrders').append(orderInfo);
// call getWorker function to display worker
var myWorkerId = allOrders.orders[i].workerId;
app.getWorker(myWorkerId);
};
};
When getWorker(myWorkerId) is called, the Ajax call inside it is not called. This is called only after iterating through the loop is done. I tried with another function inside getWorker() instead of Ajax call and this is working. Please let me know if you can spot what I am doing wrong and how this can be fixed.

making variable global by window method does not work

After looking for other answers to make a variable global I am struggeling for some time now, it looks quite simple but it just doesn't seem to work.
My code is getting data from a CSV file and returning a variable called 'chart' containing an Array. This Array variable is to be used outside the function in a Highchart graph. (The local returned Array is correct)
I am trying to make the variable inside the function "global" by attaching it as a property of the window. Like this: turn javascript local variable into global variable
But in my code this doesn't work out:
$(document).ready(function() {
$.ajax({
type: "GET",
url: "data/data.csv",
async: false,
dataType: "text",
success: function(data) {processData(data);}
});
});
function processData(data) {
var table = data.split("\n").map(line => line.split(","));
var categories = table[0].slice(2).map(e=>e*1);
data = table.slice(1).map(a => ({"name": a[0], "id": parseInt(a[1]), "data": a.slice(2).slice(0).map(e=>e*1)}));
var lengthdata = data.length - 1;
var chart = data.splice(0, lengthdata);
window.chartglobal = chart;
console.log(chart);
};
console.log(chartglobal);
What am I missing here or are there better ways than the window option for mmy specific situation?
EDIT:
The code is used in leaflet where the data is connected to leaflet markers using map.on and a marker id. That way is doesn't matter that the call ajax request is a pseudo ready event which is fired after trying to get the global value. I don't know what changing the async to 'true' alters but it works either way.
The variable is used in a map.on like this:
map.on('popupopen', function(e) {
var marker = e.popup._source.feature.id;
var search = function(name) {
for(var key in chartglobal) {
if(chartglobal[key].id === name) {
return chartglobal[key];
}}};
var outputhighchart = search(marker);
var chartdef = [];
chartdef.push(outputhighchart);});
The console.log was not logging because of the ajax call, the problem was somewhere in the map.on, which I overlooked because focusing on the global variable. Thanks for helping me out and directing in the right way.
why dont you declare your variable outside your function and give a dummy val
var chartglobal = "dummy";
$(document).ready(function() {
$.ajax({
type: "GET",
url: "data/data.csv",
async: false,
dataType: "text",
success: function(data) {processData(data);}
});
});
function processData(data) {
var table = data.split("\n").map(line => line.split(","));
var categories = table[0].slice(2).map(e=>e*1);
data = table.slice(1).map(a => ({"name": a[0], "id": parseInt(a[1]), "data": a.slice(2).slice(0).map(e=>e*1)}));
var lengthdata = data.length - 1;
var chart = data.splice(0, lengthdata);
chartglobal = chart;
console.log(chart);
};
//as #Artur Filipiak sais at this point variable is not setted yet. so should print "dummy"
console.log(chartglobal);

Accessing outer scope

I'm working on creating a Users collection with the ability to then grab single users inside. This will be used to match from another system, so my desire is to load the users once, and then be able to fine/match later. However, I'm having a problem accessing the outer users collection from an inner method.
function Users(){
var allUsers;
this.getUsers = function () {
// ajax to that Jasmine behaves
$.ajax({
url: '../app/data/jira_users.json',
async: false,
dataType: 'json',
success: function(data) {
allUsers = data;
}
});
return allUsers;
};
this.SingleUser = function (name) {
var rate = 0.0;
var position;
this.getRate = function () {
if(position === undefined){
console.log('>>info: getting user position to then find rate');
this.getPosition();
}
$.ajax({
url: '../app/data/rates.json',
async: false,
dataType: 'json',
success: function(data) {
rate = data[position];
}
});
return rate;
};
this.getPosition = function () {
console.log(allUsers);
//position = allUsers[name];
return position;
};
//set name prop for use later I guess.
this.name = name;
};
}
and the test that's starting all of this:
it("get single user's position", function(){
var users = new Users();
var someone = new users.SingleUser('bgrimes');
var position = someone.getPosition();
expect(position).not.toBeUndefined();
expect(position).toEqual('mgr');
});
The getPosition method is the issue (which might be obvious) as allUsers is always undefined. What I have here is yet another attempt, I've tried a few ways. I think the problem is how the Users.getUsers is being called to start with, but I'm also unsure if I'm using the outer and inner vars is correct.
Though the others are correct in that this won't work as you have it typed out, I see the use case is a jasmine test case. So, there is a way to make your test succeed. And by doing something like the following you remove the need to actually be running any kind of server to do your test.
var dataThatYouWouldExpectFromServer = {
bgrimes: {
username: 'bgrimes',
show: 'chuck',
position: 'mgr'
}
};
it("get single user's position", function(){
var users = new Users();
spyOn($, 'ajax').andCallFake(function (ajaxOptions) {
ajaxOptions.success(dataThatYouWouldExpectFromServer);
});
users.getUsers();
var someone = new users.SingleUser('bgrimes');
var position = someone.getPosition();
expect(position).not.toBeUndefined();
expect(position).toEqual('mgr');
});
This will make the ajax call return whatever it is that you want it to return, which also allows you to mock out tests for failures, unexpected data, etc. You can set 'dataThatYouWouldExpectFromServer' to anything you want at any time.. which can help with cases where you want to test out a few different results but don't want a JSON file for each result.
Sorta-edit - this would fix the test case, but probably not the code. My recommendation is that any time you rely on an ajax call return, make sure the method you are calling has a 'callback' argument. For example:
var users = new Users();
users.getUsers(function () {
//continue doing stuff
});
You can nest them, or you can (preferably) create the callbacks and then use them as arguments for eachother.
var users = new Users(), currentUser;
var showUserRate = function () {
//show his rate
//this won't require a callback because we know it's loaded.
var rate = currentUser.getRate();
}
var usersLoaded = function () {
//going to load up the user 'bgrimes'
currentUser = new users.SingleUser('bgrimes');
currentUser.getRate(showUserRate);
}
users.getUsers(usersLoaded);
your approach to fill the data in allUsers is flawed
the ajax call in jquery is async so every call to users.getAllUsers would be returned with nothing and when later the success function of the jquery ajax is called then allUsers would get filled
this.getUsers() won't work. Its returning of allUsers is independent from the ajax request that fetches the data, because, well, the ajax is asynchronous. Same with getRate().
You'll have to use a callback approach, where you call getUsers() with a callback reference, and when the ajax request completes, it passes the data to the callback function.
Something like:
this.getUsers = function (callback) {
// ajax to that Jasmine behaves
$.ajax({
url: '../app/data/jira_users.json',
async: false,
dataType: 'json',
success: function(data) {
callback(data);
}
});
};
And the call would be along the lines of:
var user_data = null;
Users.getUsers(function(data) {
user_data = data;
});

get a callback function to add to object javascript

I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}

Categories