Why is my object variable empty? [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 5 years ago.
All,
I have some code that uses multiple variables, objects and arrays.
Somehow my object which was filled is now empty.
var items = [];
var countryCode = "";
var message = "";
var dataset = {};
var countryData = {};
countryData.fillKey = 'NEW';
function getItems(url) {
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + url,
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
},
success: function (data) {
var items = data.d.results;
for(var i = 0; i < items.length;i++) {
countryCode = items[i].Country0.Column2;
message = countryData.fillKey;
dataset[countryCode] = message;
}
},
error: function (error) {
alert(JSON.stringify(error));
}
});
}
When I test dataset after this code it's empty. It should be something like:
dataset['UKR'] = countryData;
dataset['USA'] = countryData;
dataset['RUS'] = countryData;
Why doesn't this work?
Marco
My next code has to use the dataset:
var map = new Datamap({
element: document.getElementById('container'),
geographyConfig: {
hideAntarctica: true,
highlightFillColor: false,
popupOnHover: true,
highlightOnHover: false,
borderColor: '#000000',
borderWidth: 0.5
},
fills: {
'NEW': '#FF0000',
'OLD': '#FF7F7F',
defaultFill: '#FFFED9'
},
data: dataset
});
map.svg.call(d3.behavior.zoom().on("zoom", redraw));
function redraw() {
map.svg.selectAll("g").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
});

You can pass a callback to the getItems function to call once the request is successful.
Here is a short example of a scenario where you need to get items, then do something with that data.
function processItems() {
getItems('the/items/url', (dataset) => {
var map = new Datamap({
element: document.getElementById('container'),
geographyConfig: {
hideAntarctica: true,
highlightFillColor: false,
popupOnHover: true,
highlightOnHover: false,
borderColor: '#000000',
borderWidth: 0.5
},
fills: {
'NEW': '#FF0000',
'OLD': '#FF7F7F',
defaultFill: '#FFFED9'
},
data: dataset
});
map.svg.call(d3.behavior.zoom().on("zoom", redraw));
function redraw() {
map.svg.selectAll("g").attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
});
}
function getItems(url, callback) {
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + url,
type: "GET",
headers: {
"accept": "application/json;odata=verbose",
},
success: function(data) {
var items = data.d.results;
for (var i = 0; i < items.length; i++) {
countryCode = items[i].Country0.Column2;
message = countryData.fillKey;
dataset[countryCode] = message;
}
callback(dataset);
},
error: function(error) {
alert(JSON.stringify(error));
}
});
}

So I solved it. Sometimes things are right in front of you but you don't see it.
Just needed to set async to FALSE.
function getItems(url) {
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + url,
type: "GET",
async: false,
headers: {
"accept": "application/json;odata=verbose",
},
success: function (data) {
var items = data.d.results;
for(var i = 0; i < items.length;i++) {
countryCode = items[i].Country0.Column2;
message = countryData.fillKey;
dataset[countryCode] = message;
}
},
error: function (error) {
alert(JSON.stringify(error));
}
});
}

Related

Using variables from one script in another script in a string. Jquery/Javascript

Why does the below not work when run. I am trying to declare a variable in Script 1 I thought defining the variable outside would allow it to be global. I will say this is for a chrome application, I have the necessary permission in my manifest and I have the correct script for Jquery in my HTML.
var userName;`
and then use that in script 2 `
var text = 'Hello' + userName + 'This is a test'`
Full Code
Script 1
var userName;
var userEmail;
var userTeamName;
function currentUrl() {
return new Promise(function (resolve) {
chrome.tabs.query({
active: true,
currentWindow: true
}, function(tabs) {
resolve(tabs[0].url)
})
})
}
function userIdfromUrl(url) {
var parts = url.split('/')
return parts[parts.length - 1]
}
var authorizationToken = "xxxxxxxxxxxxxxxxxxxxxxx";
function myapiRequest(endpoint, options) {
$.ajax($.extend({}, {
type: 'GET',
dataType: "json",
success: function(data) {
$('.Name').html(data.user.name);
$('.Email').html(data.user.email);
$('.Address').html(data.user.teams[0].name);
},
url: "https://api.myapi.com/" + endpoint,
headers: {
"Authorization": "Token token=" + authorizationToken,
"Accept": "application/vnd.myapi+json;version=2"
}
},
options));
}
currentUrl()
.then(function (url) {
return userIdfromUrl(url)
})
.then(function (userId) {
return myapiRequest('users/' + userId + '?include%5B%5D=contact_methods&include%5B%5D=teams')
})
.then(function (data) {
console.log(data.user.name)
console.log(data.user.email)
console.log(data.user.teams[0].name)
jsonData = data.user.name;
of the function
})
.then(function(data) {
userName = data.user.name;
userEmail = data.user.email;
userTeamName = data.user.teams[0].name;
})
Script 2
$(document).ready(function() {
$('#contact-submit').on('click', function(e) {
e.preventDefault();
var btn = $(e.target);
btn.attr("disabled", "disabled"); // disable button
var url = 'https://hooks.slack.com/services/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
var text = 'Hello' + userName + 'This is a test'
$.ajax({
data: 'payload=' + JSON.stringify({
"text": text
}),
dataType: 'json',
processData: false,
type: 'POST',
url: url
});
});
});

Use loop in http post AngularJS asynchronous

I want to use foreach to get item by item and pass it to http post.
For example i want to get all chapters in lesson, i get this [”angularjs","react","ionic"], and i want to pass angularjs to get all chapters in
lessons of angualrjs .
Here is my code .
// asynchronous http
$scope.allLessons = [];
var init = function () {
var x = JSON.parse($localStorage.currentUser);
$http({
method: 'POST',
url: 'http://localhost/hrm/public/checkLs',
data: {email: x.email}
}).success(function (data) {
$scope.isRole.push(data);
console.log($scope.allLessons);
$scope.isRole.forEach(rr){
$http({
method: 'POST',
url: 'http://localhost/hrm/public/hpers',
data: {
name: rr
},
}).success(function (data) {
console.log(data);
}).error(function (data) {
console.log(data);
});
};
}).error(function (data) {
console.log(data);
});
};
init();
So in first http i get array of lessons [”angularjs","react"....]. and in second i get an error.
My backend get just name of lesson string not array, so how can i pass lesson by lesson for get the chapters of the lesson that i want ?
How and why is the best why to do it asynchronous ? and thanks.
For doing it synchronously , you can do something like below.
//post requests
var Requests = [
{
url:"your url1",
data:"your data"
},
{
url:"your url2",
data:"your data"
},
];
if (Requests.length>0) {
var exit = false;
var len = Requests.length-1;
executePost(0, Requests, len);
}
var executePost = function (i, Requests, len)
{
if (Requests[i]!=undefined && (i<=len))
{
var request = Requests[i];
var url = request.url;
var data = request.data;
$http.post(url, data, { headers: { "contentType": "application/json; charset=utf-8" } })
.then(function (success)
{
console.log("Processed " + (i + 1)); //processed log
//you can store the data to any variable here
if ((i + 1) <= len) {
executePost(i + 1, Requests, len);
}
},
function (error)
{
console.log("Unsuccessfull " + (i + 1));
});
}
}
Here the function executePost having three parameters is called recursively.
$scope.isRole.forEach(function(rr){
$http({
method: 'POST',
url: 'http://localhost/hrm/public/hpers',
data: {
name: rr
},
}).success(function (data) {
console.log(data);
}).error(function (data) {
console.log(data);
});
});
Use can use async waterfall in async.js. It is used to work on asynchronous call.
http://caolan.github.io/async/docs.html#.waterfall
async.waterfall([
function(callback) {
$http({
method: 'POST',
url: 'http://localhost/hrm/public/checkLs',
data: { email: x.email }
}).success(function(data) {
$scope.isRole.push(data);
console.log($scope.allLessons);
callback(null, isRole);
});
},
function(isRole, callback) {
// arg1 now equals 'one' and arg2 now equals 'two'
isRole.forEach(rr) {
$http({
method: 'POST',
url: 'http://localhost/hrm/public/hpers',
data: {
name: rr
},
}).success(function(data) {
console.log(data);
callback(null, data);
}).error(function(data) {
callback(err, null);
});
};
}
],
function(err, result) {
// result now equals 'done'
});

Setting dynamic fallback in jquery each with JSON data

I am trying to set a fallback function dynamically from an ajax jsonp call, but it doesn't seem to work - I am actually not quite sure if it is even possible - at least I believe I am doing it wrong.
I have this
var GetFacebookData = function (data) {
var dates = [{ "date_from": data.date_from, "date_to": data.date_to }]
$.each(data.datatypes, function (i, index) {
this.fbcallback[data.datatypes[i]["id"]] = function () {
LoadFacebookData(dates, data.datatypes["id"]);
}
$.ajax({
url: 'http://localhost:59380/' + data.datatypes[i]["urlfile"] + '.php?jsonp=fbcallback' + data.datatypes[i]["id"],
method: 'GET',
dataType: 'jsonp',
jsonp: 'fbcallback',
data: { "lpage": _bankArea, "hashed_token": CryptoJS.MD5("454545").toString(), "date_from": data.date_from, "date_to": data.date_to },
});
});
}
And I am calling the function with this
GetFacebookData({ date_from: _datefrom, date_to: _dateto, datatypes: [{ id: "moedsparnord", urlfile: "index" }, { id: "studiepakken", urlfile: "fb_studiedata" }] });
I am just getting
Uncaught TypeError: Cannot set property 'moedsparnord' of undefined
The whole concept is that I will need to run GetFacebookData multiple times with difference data to be executed.
/*** LOAD FETCHED DATA AS JSON ***/
var LoadFacebookData = function (dates, id) {
_dateLoader.hide();
$('.date-box form').slideUp(750, 'easeOutBack');
var pages = [];
this.loadcallback = function (data) {
var len = data["campaignData"].length;
$.each(data["campaignData"], function (index, value) {
$('#' + id + '-' + value["campaign"]["campaignId"]).find(".facebook").text(AddDecimal(value["campaign"]["campaignReach"]));
$('#' + id + '-' + value["campaign"]["campaignId"]).find(".facebook").attr("data-spend", value["campaign"]["campaignSpend"]);
if (index != len) {
pages[index] = [value["campaign"]["campaignId"], value["campaign"]["campaignSpend"]];
}
});
var string = $('#' + id + ' .total-facebook').text().replace(/,/g, '');
$("#" + id + " .total-facebook").countTo({
from: parseFloat(string),
to: data["totalReach"],
decimals: 0,
formatter: function (value, options) {
return value.toFixed(options.decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ".");
},
});
MSNLeadData([{ date_from: dates[0]["date_from"], date_to: dates[0]["date_to"] }, pages]);
StudieLeadData([{ date_from: dates[0]["date_from"], date_to: dates[0]["date_to"], pages }]);
}
$.ajax({
url: 'http://localhost:59380/loaddata.php?jsonp=loadcallback',
method: 'GET',
dataType: 'jsonp',
jsonp: 'loadcallback',
data: { "lpage": _bankArea, "hashed_token": CryptoJS.MD5("454545").toString(), "datatype": id },
});
}
Functions fbcallback['...'] should be global.
Try to use this code inside the loop.
...
var callbackName = 'fbcallback-' + data.datatypes[i]["id"];
window[callbackName] = function () {
LoadFacebookData(dates, data.datatypes["id"]);
}
...
$.ajax({
url: 'http://localhost:59380/' + data.datatypes[i]["urlfile"] + '.php',
method: 'GET',
dataType: 'jsonp',
jsonp: callbackName,
data: { "lpage": _bankArea, "hashed_token": CryptoJS.MD5("454545").toString(), "date_from": data.date_from, "date_to": data.date_to },
});
And inside of LoadFacebookData callback method should also be global (window.loadcallback).

says my function is undefined when assigning to a variable

i have a problem. I am trying to add a functions return value to a variable but it says the function is undefined. Here is my code. :
var selectedExpenseList = getSelectedExpenseIDs();
here is my function:
function getSelectedExpenseIDs() {
var selectedExpensesList = new Array;
var i = 0;
$('.expenseCheckBox:checked').each(function () {
if ($(this)[0].id !== "checkAllExpenses") {
selectedExpensesList[i] = $(this)[0].id.split('_')[1];
++i;
}
});
return selectedExpensesList;
}
EDIT: here is my entire function: I am trying to delete something from a list if a person has checked it.
var selectedExpenseList;
function actuallyDeleteTheExpense(canDeleteExpenses)
{
selectedTasksList = getSelectedTaskIDs();
var deleteTrackers = false, deleteExpenses = false;
if (canDeleteExpenses && !canDeleteTrackers)
{
$.Zebra_Dialog('Do you wish to remove Expenses?',
{
'type': 'question',
'title': 'Confirmation',
'buttons': [
{
caption: 'Yes', callback: function () {
deleteTrackers = false;
deleteExpenses = true;
doTheDelete(deleteExpenses);
}
},
{
caption: 'No',
callback: function () {
doTheDelete(deleteExpenses);
}
}
]
});
}
}
function doTheDelete(doIDeleteExpenses)
{
if (selectedTasksList.length > 0)
{
$.ajax({
type: "POST",
//url: "/Tasks/ViewTasks.aspx/deleteTasksAndLinkedItems",
url: '<%=ResolveUrl("~/Expenses/ViewExpenses.aspx/deleteSelectedExpense")%>',
data: "{ 'TaskIDs': [" + selectedTasksList.join(',') + "], DeleteTrackers : " + doIDeleteTrackers + ", DeleteExpenses : " + doIDeleteExpenses + " }",
//fix data
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
var ss = data.d;
if (ss.length > 0) {
for (var i = 0; i < ss.length; ++i) {
$.noty.consumeAlert({ layout: 'center', type: 'error', dismissQueue: true });
alert(ss[i]);
}
}
$("#viewTasksGrid").flexReload();
},
error: function (data) {
$.noty.consumeAlert({ layout: 'center', type: 'error', dismissQueue: true, modal: true });
alert('Error Deleting Tasks');
if (window.console) {
console.log(data);
}
}
});
} else {
showMessage('No tasks are selected.');
}
}
//end delete expense
function getSelectedExpenseIDs() {
var selectedExpensesList = new Array;
var i = 0;
$('.expenseCheckBox:checked').each(function () {
if ($(this)[0].id !== "checkAllExpenses") {
selectedExpensesList[i] = $(this)[0].id.split('_')[1];
++i;
}
});
return selectedExpensesList;
}
I noticed that your function code is tabbed once more than your code that calls it. It's possible that your function is scoped improperly (e.g. it's declared inside another function and you're calling it from outside that function).
If your function is coming back as undefined, it's almost certainly a scoping issue. I see nothing wrong with the function itself.
For instance:
$(document).ready(function () {
function myFunction() {
return 3;
}
});
var bob = myFunction(); //Error: myFunction is not defined.

Javascript OOP inheritance not working

So I am writing something using augment for inheritance and for some reason I can run this.setButtons(type) and console.log(this.buttons) in that method, but when I run my this.getButtons() it comes back as undefined, even though getButtons just returns this.buttons. Any help would be greately appreciated. I will post up all the code I have so far, because maybe I'm not inheriting properly. Thank you in advance.
var ContextMixin = function () {};
ContextMixin.prototype = {
createElements: function (el, mode, type) {
var m;
if (mode == 'exact') {
$("#" + el).append("<ul id='contextmenu'>");
} else {
$(el).each(function () {
m = $(this).append("<ul id='contextmenu'>");
});
$('body').append(m);
}
$("#contextmenu").css({
'position': 'absolute',
top: 13,
left: 13
});
var new_buttons = this.getButtons();
$.each(this.buttons['buttons'], function () {
m.append("<li id='" + this + "'>" + this + "</li>");
});
},
attachEvents: function () {
functions = this.getFunctions(type);
buttons = this.getButtons();
for (index in buttons['buttons']) {
addEvent(buttons['buttons'][index], this.functions[index][0], this.functions[index][1]);
};
},
setFunctions: function (type) {
var callback = {
success: function (msg) {
this.functions = msg;
},
failure: function () {
alert('Error getting functions')
}
};
$.ajax({
type: 'GET',
url: 'function_list.php?type=' + type,
success: function (msg) {
this.functions = msg;
}
});
},
getFunctions: function () {
return this.functions;
},
setType: function (value) {
this.type = value;
},
getType: function () {
return this.type;
},
setButtons: function (type) {
$.ajax({
type: 'GET',
url: 'button_list.php?type=' + type,
success: function (reply) {
this.buttons = reply;
}
});
},
getButtons: function () {
return this.buttons;
}
}
function createMenu(el, type, mode) {
this.setButtons(type);
this.setFunctions(type);
this.createElements(el, mode, type);
}
augment(createMenu, ContextMixin);
function augment(receivingClass, givingClass) {
if (arguments[2]) { //Only give certain methods.
for (var i = 2, len = arguments.length; i < len; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
}
} else { //Give all methods
for (methodName in givingClass.prototype) {
if (!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName];
}
}
}
}
Because this in the callback to the AJAX request is not your object.
Here's a common fix...
setButtons: function(type) {
var self = this; // keep a reference to this
$.ajax({
type: 'GET',
url: 'button_list.php?type=' + type,
success: function(reply) {
self.buttons = reply; // use the reference here
}
});
},
...but a better fix is to use the context: property of the $.ajax request...
setButtons: function(type) {
$.ajax({
type: 'GET',
context: this, // set the context of the callback functions
url: 'button_list.php?type=' + type,
success: function(reply) {
this.buttons = reply;
}
});
},
If you change
ContextMixin.prototype = {
createElements
to
ContextMixin.prototype.createElements
it should work.
this is not what you think it is in your ajax callback—instead of being your current object, it's actually the global object the XHR object. All your callback is doing is putting a buttons property onto the xhr object.
You need to save this before your function runs:
setButtons: function(type) {
var self = this;
$.ajax({
type: 'GET',
url: 'button_list.php?type=' + type,
success: function(reply) {
alert(reply);
self.buttons = reply;
}
});
},

Categories