Cant access object that have been declare on javascript - javascript

I'm trying to get some value over my server using jquery's $.get method and store the result in an object.
What I'm doing is running my function inside a loop:
function renderTabelScheduledEmploye(employees) {
$('#containerDataStaff').empty();
let record = '';
let count = 1;
if (employees.length > 0) {
$.each(employees, function(key, value) {
getFromServerScheduleCount(employees[key].schedule_employee_id);
console.log(scheduleCountData);
record += '<tr>';
record += '<td>' + count + '</td>';
record += '<td>( ' + employees[key].emp_kode + ') - ' + employees[key].emp_full_name + '</td>';
record += '<td>' + scheduleCountData[0].work + '</td>';
record += '<td>' + scheduleCountData[0].offDay + '</td>';
record += '<td>' + scheduleCountData[0].leave + '</td>';
record += '<td>' + scheduleCountData[0].shiftCount + '</td>';
record += '<td>Set Shift</td>';
record += '</tr>';
count++;
});
}
$('#containerDataStaff').append(record);
}
Then I create a function to retrieve JSON data from my server using the $.get function, then store the data result to an object that has been declared:
var scheduleCountData = new Object();
function getFromServerScheduleCount(schedule_employee_id) {
let url = `{{ url('/departement/schedule/manage/schedule/count') }}`;
url = url + '/' + schedule_employee_id + '/get';
let data = {};
$.get(url, function(data) {
let obj = JSON.parse(data);
data.work = obj.work;
data.dayOff = obj.dayOff;
data.leave = obj.leave;
data.shifts = obj.shifts;
scheduleCountData.new = data;
})
}
I can see in the console that the object has filled with the data
[object success to fill][1]
But when i try to access in code like this
scheduleCountData[0]
and log the result to to the console, it shows undefined.
This little bit frustrating for me. I hope someone can help me. Thanks for community.
EDIT :
Sorry i miss
i try to call that object with code like this
scheduleCountData.new
but still undefined on console

Seems youre not waiting for the load to finish before trying to use the data:
// This has a get call, which is async (takes time to load)
getFromServerScheduleCount(employees[key].schedule_employee_id);
// The script will continue, without waiting for the load to finish, so can be empty
console.log(scheduleCountData);
I would suggest adding a callback, like this:
getFromServerScheduleCount(employees[key].schedule_employee_id, function(scheduleCountData) {
console.log(scheduleCountData);
});
function getFromServerScheduleCount(schedule_employee_id, callback) {
$.get(url, function(data) {
// ...
callback(data);
});
}

Related

i want to seperate a function into a multiple function jquery/ajax

I have a JavaScript file that has an Ajax function which calls a JSON file from an online server to extract it's data and interpret it in to a generated table... I want to separate the generate link, generate date, identify the car plate type/country into multiple functions that can be called by the ajax function.
// table of the server's data from JSON file
$(document).ready(function() {
$.ajax({
url: "http://127.0.0.1:3737/anpr?nb=0",
type: "GET",
dataType: "json",
success: function(data) {
var detection_data = '';
// generating the table to interpret the json data
$.each(data, function(key, value) {
detection_data += '<div class="table-row">';
detection_data += '<div class="serial">' + value.id + '</div>';
// identifie the car plate type/country fron json data
var plateType = value.plateType
if (plateType == "1") {
detection_data += '<div class="country">Tunisie TN</div>';
} else if (plateType == "2") {
detection_data += '<div class="country">Tunisie RS</div>';
} else if (plateType == "3") {
detection_data += '<div class="country">Tunisie GOV</div>';
} else if (plateType == "4") {
detection_data += '<div class="country">Lybie</div>';
} else if (plateType == "5") {
detection_data += '<div class="country">Algerie</div>';
} else {
detection_data += '<div class="country">Autre</div>';
}
detection_data += '<div class="visit">' + value.plateNumber + '</div>';
// generate date from json data
detection_data += '<div class="percentage">' + value.date.substr(8, 2) +
'/' + value.date.substr(5, 2) + '/' + value.date.substr(0, 4) +
' ' + value.date.substr(11, 2) + ':' + value.date.substr(14, 2) + ':' + value.date.substr(17, 2) + '</div>';
// generate link
detection_data += '<div>' + '<a class="img-pop-up" href="http://127.0.0.1:3737/anpr/snapshot?year=' + value.date.substr(0, 4) +
'&month=' + value.date.substr(5, 2) + '&day=' + value.date.substr(8, 2) +
'&&hour=' + value.date.substr(11, 2) + '&minute=' + value.date.substr(14, 2) + '&second=' + value.date.substr(17, 2) +
'&plate=' + value.plateNumber.split(" ").join("_") + '&platetype=' + value.plateType + '">link to picture</a>' + '</div>';
detection_data += '</div>';
});
$('#detection_table').append(detection_data);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
I tried to make your code more modular and readable. Here's what I could come up with. I am posting only relevant sections of your code to be concise.
NOTE: This is just a recommendation,I have not tested the below code.
var detection_data = '';
// generating the table to interpret the json data
$.each(data, function(key, value) {
detection_data += '<div class="table-row">';
detection_data += getPlateIDHTML(value.id);
// identifie the car plate type/country fron json data
detection_data += getPlateTypeCountryHTML(value.plateType);
// Plate number
detection_data += getPlateNumberHTML(value.plateNumber);
// generate date from json data
detection_data += getDetectionDateHtml(value.date);
// generate link
detection_data += getSnapshotLink(value.date, value.plateNumber, value.plateType);
detection_data += '</div>';
});
$('#detection_table').append(detection_data);
Below are my functions
String.prototype.format = function () {
var a = this, b;
for (b in arguments) {
a = a.replace(/%[a-z]/, arguments[b]);
}
return a; // Make chainable
};
function parseStringAsJSDate(date_as_string) {
return new Date(date_as_string);
}
function getPlateIDHTML(id) {
var plate_id_html = '<div class="serial">%s</div>';
return plate_id_html.format(id);
}
function getPlateNumberHTML(plateNumber) {
var plate_number_html = '<div class="visit">%s</div>';
return plate_number_html.format(plateNumber);
}
function getPlateTypeCountryHTML(plateType) {
var plateTypeCountry = {
"1": "Tunisie TN",
"2": "Tunisie RS",
"3": "Tunisie GOV",
"4": "Lybie",
"5": "Algerie",
};
var plate_type_country_html = '<div class="country">%s</div>';
if(plateType in plateTypeCountry) {
return detection_data_html.format(plateTypeCountry[plateType]);
} else {
return detection_data_html.format("Autre");
}
}
function getDetectionDateHtml(captured_date_as_string) {
var date_of_capture_html = '<div class="percentage">%s/%s/%s %s:%s:%s</div>';
var captured_date = parseStringAsJSDate(captured_date_as_string);
return date_of_capture_html.format(captured_date.getDate(), captured_date.getMonth()+1, captured_date.getFullYear(), captured_date.getHours(), captured_date.getMinutes(), captured_date.getSeconds());
}
function getSnapshotLink(captured_date_as_string, plateNumber, plateType) {
var snapshot_link = "http://127.0.0.1:3737/anpr/snapshot?year=%s&month=%s&year=%s&day=%s&hour=%s&minute=%s&second=%s&plate=%s&platetype=%s";
var snapshot_link_html = '<div><a class="img-pop-up" href="%s">Link to picture</a></div>';
var captured_date = parseStringAsJSDate(captured_date_as_string);
var snapshot_link = snapshot_link.format(captured_date.getDate(), captured_date.getMonth()+1, captured_date.getFullYear(), captured_date.getHours(), captured_date.getMinutes(), captured_date.getSeconds(), plateNumber.split(" ").join("_"), plateType);
return snapshot_link_html.format(snapshot_link);
}
Below is a brief explanation of each function
String.prototype.format: This is an equivalent of the old-school printf in C. I find variable-substitutions of the sort '<div class="serial">'+ id +'</div>' inter-mingling HTML with JavaScript very difficult to read. And therefore this.
parseStringAsJSDate: I assume that your API is under your control. I recommend you to modify the date format to ISO8601 so that it can be parsed by JavaScript as a Date. Your substr function again affects readability.
getPlateIDHTML & getPlateNumberHTML: Simple functions that just use the format function to embed the passed variables into the HTMLs to show ID and plate number.
getPlateTypeCountryHTML: I used a Python object here to reduce the number of ifs and else ifs.
getDetectionDateHtml & getSnapshotLink: I have tried to parse the date as a JavaScript date and this eliminates the substrs. Moreover, the use of format simplifies these functions further.
Let me know your suggestions on this. Suggestions/Criticism from Stack's gurus are more than welcome :)
UPDATE
Please check my updated format function. I sourced it from this excellent answer. Apologies, the earlier one was just copy-pasted, I should have tried it. Please just the format function to the one that's indicated and let me know

How to recursively build a list using a callback and iterating through the children?

I'm unsure on how to build this list (which is a string) and then returning as one complete string.
I've worked past my last issue but I think this one is realy bugging me. buildItem() should iterate through item, and then recursively build a list while getting the totalCost from another callback. I know it works asynchronously...
buildItem(data, function(html){
$('#nestable ol').append(html);
});
Should append the 'final' html string that's created from being appended throughout the file.
function buildItem(item, callback) {
getTotalCost(item, function(totalCost) {
var html = "<li class='dd-item' data-id='" + item.id + "' data-email='" + item.email + "' data-title='" + item.corporateTitle + "' data-name='" + item.firstName + " " + item.lastName + "' id='" + item.id + "'>";
if (item.children && item.children.length > 0) {
html += "<ol class='dd-list'>";
$.each(item.children, function (index, sub) {
buildItem(item, function(subHtml){
html += subHtml;
})
})
html += "</ol>";
}
html += "</li>";
callback(html);
});
}
I know that
buildItem(item, function(subHtml){
html += subHtml;
})
shouldn't work since javascript is asynchronous. I'm just not sure on how to return from a recursive function? If I were to do something like
buildItem(item, function(subHtml){
callback(subHtml);
})
You'll get duplicate values because you'll have the starting value and it's children, but since you're also calling it back you'll get the children outside of the starting value. So it'll look like
1
a
b
c
d
e
a
b
c
d
e
So what's the best way to approach a solution? I was thinking of making another function, hypothetically a buildChild(sub) that returned html, but the same issue with asynchronous is going to come up where the return will be undefined. I've read some of the threads where you can handle asynchronous values with callbacks, but I'm not sure on how to do it with recursion here.
getTotalCost is another callback function that shouldn't mean much, I removed the line by accident but I just need the totalCost from a database.
function getTotalCost(item, callback) {
$.ajax({
dataType: "json",
url: "/retrieveData.do?item=" + item.email,
success: function(data) {
var totalCost = 0;
for (var i = 0; i < data.length; i++) {
totalCost += parseFloat(data[i].cost);
}
callback(totalCost);
}
});
}
You can simplify this with promises and async functions:
async function getTotalCost(item) {
const data = await Promise.resolve($.ajax({
dataType: "json",
url: "/retrieveData.do?item=" + item.email
}));
return data.reduce((acc, next) => acc + next.cost, 0);
}
async function buildItem(item) {
const totalCost = await getTotalCost(item);
let html = `<li class="dd-item" data-id="${item.id}" data-email="${item.email}" data-title="${item.corporateTitle}" data-name="${item.firstName} ${item.lastName}" id="${item.id}">`;
if (item.children && item.children.length > 0) {
html += '<ol class="dd-list">';
for (const childItem of item.children) {
html += await buildItem(childItem);
}
html += "</ol>";
}
html += "</li>";
return html;
}
Unfortunately, async functions aren't supported by all browsers yet, so you'll have to use Babel to transpile your code.
I also added some new ES6 features: arrow functions, const and template literals.
You can mix slow ajax requests with logic and recursion if you execute your code via synchronous executor nsynjs.
Step 1. Write your logic as if it was synchronous, and place it into function:
function process(item) {
function getTotalCost(item) {
var data = jQueryGetJSON(nsynjsCtx, "/retrieveData.do?item=" + item.email).data;
var totalCost = 0;
for (var i = 0; i < data.length; i++) {
totalCost += parseFloat(data[i].cost);
}
return totalCost;
};
function buildItem(item) {
const totalCost = getTotalCost(item);
var html = "<li class='dd-item' data-id='" + item.id + "' data-email='" + item.email + "' data-title='" + item.corporateTitle + "' data-name='" + item.firstName + " " + item.lastName + "' id='" + item.id + "'>";
if (item.children && item.children.length > 0) {
html += '<ol class="dd-list">';
for (var i=0; i<item.children.length; i++)
html += buildItem(item.children[i]);
html += "</ol>";
}
html += "</li>";
return html;
};
return buildItem(item);
};
Step 2: run it via nsynjs:
nsynjs.run(process,{},item,function (itemHTML) {
console.log("all done",itemHTML);
});
Please see more examples here: https://github.com/amaksr/nsynjs/tree/master/examples

Jquery: Global variable or function not returning data

I am at my wits end here.
I am trying to build a report which retrieves data from a JSON array. Which is stored in a local stored file (using HTML5 FileAPI).
I have divided the build into two functions: Report and FileReader
I am able to read the file, and send the content to console.log inside the FileReader function. But I am NOT ABLE to send that data outside the function. I've tried so many different approaches that I've lost count on which and how many. I tried Global Variable, but that stays blank outside the FileReader Function. I tried Promise.deferred etc. etc.
Please help!
var JsData = '';
function fileReader(hente) {
var deferred = $.Deferred();
fs.root.getFile(hente, {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.readAsText(file, "utf-8");
reader.onloadend = function(e) {
JsData = this.result;
console.log('JsData: ' + JsData ); //Check that data has been read
// try this
//return JsData;
// Try Defferred
return deferred.promise(JsData);
};
}, errorHandler);
}, errorHandler);
};
function createDokument(dokName) {
var ClientTable = '';
var kake = Cookies.get(dokNavn);
var visits = JSON.parse(kake);
$.each(visits, function(index, value) {
var hente = value.dok + '_' + value.nr;
//Make sure the variable is blank, for no reason at all
JsData = '';
var promise = fetchVisitInfo(hente + '.oln');
promise.then(function(result) {
/// Test if variable has retrieved the data
console.log('JsData: ' + JsData );
$.each(JsData, function (i,v) {
ClientTable += ' <tr>';
ClientTable += ' <td colspan="3">' + v['orderSum'].Knr + ', ' + v['orderSum'].firma + '</td>';
ClientTable += ' <td width="3%">' + v['orderSum'].oldV + v['orderSum'].newV + '</td>';
ClientTable += ' <td width="15%">' + v['orderSum'].newS + '</td>';
ClientTable += ' <td width="15%">' + v['orderSum'].oldS + '</td>';
ClientTable += ' </tr>';
});
});
});
Any ideas ??

JavaScript Callbacks for multiple functions

I'm currently trying to take results I have from an api controller, and have that json data added to a table in my razor view. I had some issues with the array I was using to fill the table not being filled with data before the table was created. I've tried to absolve that problem with callbacks, but I'm still inexperienced, and having trouble understanding from tutorials.
Here are the javascript function I have (and in order they must go 1. the $.getJson 2. the fillArray function 3. the AddToTable function) :
$(document).ready(function ()
{
$.getJSON('api/GetRestaurants/detroit').done(fillArray(data))
});
function fillArray(data, callback)
{
var restaurant =
{
Name: "",
PhoneNumber: "",
PlaceID: "",
Rating: 0,
Website: ""
};
var dataArray = new Array();
for (var k = 0; k < data.length; k++) {
restaurant.Name = data[k].Name;
restaurant.PhoneNumber = data[k].PhoneNumber;
restaurant.PlaceID = data[k].PlaceID;
restaurant.Rating = data[k].Rating;
dataArray.push(restaurant);
}
callback(AddToTable(dataArray));
}
function AddToTable(dataArray) {
document.getElementById("tbl").innerHTML =
'<tr>' +
'<th>Restaurant Name</th>' +
'<th>Restaurant PlaceID</th>'
for (var i = 0; i < dataArray.length; i++) {
+'<tr>'
+ '<td>' + dataArray[i].Name + '</td>'
+ '<td>' + dataArray[i].PlaceID + '</td>'
+ '</tr>';
}
}
The data is there, and the api controller call is successful, I just need to data to fill the array before the table uses that array.
I appreciate any help and/or comments, thanks guys :].
When you do the following:
$.getJSON('api/GetRestaurants/detroit').done(fillArray(data))
You are calling the fillArray() function and passing its result to the .done() function. Instead, you should be passing the fillArray function to the .done() function.
$.getJSON('api/GetRestaurants/detroit').done(fillArray)
I prefer to use an anonymous function when setting a callback. Then the named functions can have the signatures that make sense for them. The anonymous callback function, of course, has the signature required for it. The named functions are then called inside the anonymous callback function.
$(document).ready(function() {
$.getJSON('api/GetRestaurants/detroit').done(function(data) {
var restaurants = createRestaurantArray(data);
addRestaurantsToTable(restaurants);
});
});
function createRestaurantArray(apiData) {
var restaurants = []; // Preferred syntax over "new Array()"
for (var i = 0; i < apiData.length; i++) {
restaurants.push({
Name: apiData[i].Name,
PhoneNumber: apiData[i].PhoneNumber,
PlaceID: apiData[i].PlaceID,
Rating: apiData[i].Rating,
Website: ""
});
return restaurants;
}
function addRestaurantsToTable(restaurants) {
var html = '<tr>'
+ '<th>Restaurant Name</th>'
+ '<th>Restaurant PlaceID</th>'
+ '</tr>';
for (var i = 0; i < restaurants.length; i++) {
html += '<tr>'
+ '<td>' + restaurants[i].Name + '</td>'
+ '<td>' + restaurants[i].PlaceID + '</td>'
+ '</tr>';
}
$('#tbl').html(html);
}
Also, your fillArray() function was creating a single restaraunt object and pushing that same object to the array for each iteration of the for-loop. That means the resulting array would contain the same object over and over, and that object would have the property values set by the last iteration of the loop.
All the commands in your fillArray function appear to be synchronous (i.e. the code does not move on until they are completed) so as long as this is called before your function to add the data you should be okay.

jQuery JSON database variable applied in Javascript

This could be an easy task but I am just learning the relationship between jQuery, JSON, and Javascript. I used jQuery to to pull from my database and create a variable called res[i].showlink which is a url. Here is part of my code for the call.
$.get("http://databasecall=json", {}, function (res) {
$.mobile.hidePageLoadingMsg();
if (res.length) {
var s = "";
for (var i = 0; i < res.length; i++) {
s += "<li><a name=" + res[i].id + " href='" + "javascript:openGoogle()" + "'>" + res[i].showlink + "</a></li>";
}
$("#showList").html(s);
$("#showList").listview("refresh")
}, "json");
The problem is that I would like reuse the res[i].showlink database variable in a javascript function (openGoogle) outside of the code above. When I go to reuse the database variable res[i].showlink, it no longer contains my data from the database. How can I reuse the variable outside of the jQuery/JSON code above? I really appreciate any suggestions. Thank you!
You are storing that value as the contents of the anchor tag, you can access it from there too.
change
javascript:openGoogle()
to
javascript:openGoogle.apply(this)
and then inside of openGoogle, you can access the value with $(this).text()
Edit
Another option is to pass the value directly as a parameter.
change
javascript:openGoogle()
to
javascript:openGoogle(" + res[i].showlink + )
and then modify
function openGoogle() {
to
function openGoogle(showlink) {
and access the value with
alert(showlink);
You need to store a reference to res outside of the get call--otherwise, it's scoped and, as you noticed, you can't access it from outside the call. Try something like this:
var globalRes = null;
$.get("http://databasecall=json", {}, function(res) {
globalRes = res;
$.mobile.hidePageLoadingMsg();
if (res.length) {
var s = "";
for (var i = 0; i < res.length; i++) {
s += "<li><a name=" + res[i].id + " href='" + "javascript:openGoogle()" + "'>" + res[i].showlink + "</a></li>";
}
$("#showList").html(s);
$("#showList").listview("refresh")
}, "json");​
After the call, globalRes will contain the value of res, but will be global, meaning you can access it from outside the get call.
save the value in the global variable:
$.get("http://databasecall=json", {}, function (res) {
window.myResult = res;
....
}
and use it afterwards
You need to store it in a variable that has scope outside of the ajax return call.
So for example you could have:
var resData;
at the top of an included javascript file
then replace your code with
$.get("http://databasecall=json", {}, function(res) {
$.mobile.hidePageLoadingMsg();
if(res.length){
resData = res;
var s = "";
for(var i=0; i<res.length; i++) {
s+= "<li><a name=" + res[i].id + " href='" + "javascript:openGoogle()" + "'>" + res[i].showlink + "</a></li>";
}

Categories