JQuery Mobile not executing my entire function - javascript

I'm trying to add a listview element based on my QR code. So when I scan one QR code, i take the first value of the array, and add a listview element with the text of the first value, and use a counter and so on. However, it doesn't increment my counter. All i get is that the function appendToList() gets terminated once listview refreshes. Count doesnt increment and ArrayIndex remains empty. How can I get the counter to work? And the array as well? The function doesn't execute all the way.
function scan() {
cordova.plugins.barcodeScanner.scan(
function(result) {
$("#nullExhibition").remove();
resetData(); // Removes the empty exhibition text
if (!result.cancelled) {
if (result.format == "QR_CODE") {
var value = result.text;
if(!localStorage.getItem("LocalData"))localStorage.setItem("LocalData","[]")
data = localStorage.getItem("LocalData");
//alert(data);
data = JSON.parse(data);
data.push(value);
localStorage.setItem("LocalData", JSON.stringify(data));
//location.reload();
alert(count);
appendToList();
// location.hash = '#Vote';
}
}
},
function(error) {
alert("Scanning failed: " + error);
}
);
}
//JJJ Function: creates table which will be refreshed in the homePage //CW Create the listview if not created
function appendToList() {
$("#list").append("<li id='" + count + "' style='font-family: 'Quicksand', sans-serif !important;' class='ui-content'><a href='javascript:pageGenerator()'>" + data[0] + "</a></li>");
$("#list").listview("refresh");
ArrayIndex.append(data[0]);
count ++;
}
function resetData(){
localStorage.removeItem("LocalData");
}

Where did you declare "count" in the global scope? You reference it in two separate functions, but are neither passing the value between them, nor made it a global var so that both functions reference the same variable. They way you have it, you reinitialize that var each time that you call the appendToList() function.
Add this to the top of your document (outside of the function closures):
var count = 0;

Related

Global var is being reset by each for loop iteration instead of updating

Disclosure: I'm fairly new and inexperienced with JS, but I have spent hours trying to find a solution to this via Stackoverflow and other internet resources. My mentor is away this week, so I am hoping someone here will be able to help me. Thank you in advance!
Intro: I'm trying to keep track of a running total via variable setupTotal. I placed it at the top of the function getStoredData, thinking that it would act like a global and not be over-written or reset during the for loop within getStoredData. I've included the surrounding code for context and bolded what I thought pertained to the actual issue I'm having.
The Issue: Every time the for loop cycles though an iteration, my setupTotal variable is being reset. I see this both in the console log and in the setupFees.innerHTML at the end of the buildSetup function. From what I understand, when I specify var setupTotal = 0; at the beginning of the getStoredData function, the updates I'm making in the buildSetup nested function should be over-writing the original value. Yet, each time a new iteration runs, the setupTotal value is starting at 0 again.
function getStoredData() {
// Builds "Service Row" div to house the incoming content
buildDivRow();
var setupTotal = 0;
// Loops through the boxes to see what's stored
for (var service in serviceDatabase) {
for (id=0; id < serviceDatabase[service].length; id++) {
console.log("Starting " + service + ": " + serviceDatabase[service][id]);
// Get the stored data if it exists
var inputID = service + "-input-" + id;
var getData = localStorage.getItem(inputID);
console.log("Attempting data retrieval for " + inputID + ": " + getData);
// Passes the info to a function that creates the HTML to display stored data
if (getData != null) {
// Passes the info to functions that captures "total" data
console.log("buildSetup starting, service: " + service);
console.log("buildSetup starting, getData: " + getData);
console.log("buildSetup starting, setupTotal): " + setupTotal);
buildSetup(service, getData, setupTotal);
// Passes the info to a function that builds the div containers
buildDivXs12(getData, inputID, service, id);
// Logs that the data was found successfully or not
console.log("Retrieved ID (" + inputID + ") and data (" + getData + ")");
} else {
console.log("No data to retrieve for " + serviceDatabase[service][id] + ": " + inputID );
}
}
}
}
// Keeps track of the setup fees
function buildSetup(service, getData, setupTotal) {
// Retrieve the setup fee
var setup = setupDatabase[service][getData];
console.log("buildSetup ending, setup: " + setup);
// Update the setupTotal global var
setupTotal = parseInt(setupTotal) + parseInt(setup);
console.log("buildSetup ending, setupTotal): " + setupTotal);
// Update the setupFees inner HTML
var setupFees = document.getElementById("setupFee");
setupFees.innerHTML = setupTotal;
}
Base on your code, what you can do is return the setupTotal value on buildSetup function then assign it after it's called on your getStoredData function like this:
function getStoredData() {
..
console.log("buildSetup starting, setupTotal): " + setupTotal);
setupTotal = buildSetup(service, getData, setupTotal);
..
}
function buildSetup(service, getData, setupTotal) {
..
setupFees.innerHTML = setupTotal;
return setupTotal;
}

Twitch TV JSON API Issue

So,I am trying to use the twitch API:
https://codepen.io/sterg/pen/yJmzrN
If you check my codepen page you'll see that each time I refresh the page the status order changes and I can't figure out why is this happening.
Here is my javascript:
$(document).ready(function(){
var ur="";
var tw=["freecodecamp","nightblue3","imaqtpie","bunnyfufuu","mushisgosu","tsm_dyrus","esl_sc2"];
var j=0;
for(var i=0;i<tw.length;i++){
ur="https://api.twitch.tv/kraken/streams/"+tw[i];
$.getJSON(ur,function(json) {
$(".tst").append(JSON.stringify(json));
$(".name").append("<li> "+tw[j]+"<p>"+""+"</p></li>");
if(json.stream==null){
$(".stat").append("<li>"+"Offline"+"</li>");
}
else{
$(".stat").append("<li>"+json.stream.game+"</li>");
}
j++;
})
}
});
$.getJSON() works asynchronously. The JSON won't be returned until the results come back. The API can return in different orders than the requests were made, so you have to handle this.
One way to do this is use the promise API, along with $.when() to bundle up all requests as one big promise, which will succeed or fail as one whole block. This also ensures that the response data is returned to your code in the expected order.
Try this:
var channelIds = ['freecodecamp', 'nightblue3', 'imaqtpie', 'bunnyfufuu', 'mushisgosu', 'tsm_dyrus', 'esl_sc2'];
$(function () {
$.when.apply(
$,
$.map(channelIds, function (channelId) {
return $.getJSON(
'https://api.twitch.tv/kraken/streams/' + encodeURIComponent(channelId)
).then(function (res) {
return {
channelId: channelId,
stream: res.stream
}
});
})
).then(function () {
console.log(arguments);
var $playersBody = $('table.players tbody');
$.each(arguments, function (index, data) {
$playersBody.append(
$('<tr>').append([
$('<td>'),
$('<td>').append(
$('<a>')
.text(data.channelId)
.attr('href', 'https://www.twitch.tv/' + encodeURIComponent(data.channelId))
),
$('<td>').text(data.stream ? data.stream.game : 'Offline')
])
)
})
})
});
https://codepen.io/anon/pen/KrOxwo
Here, I'm using $.when.apply() to use $.when with an array, rather than list of parameters. Next, I'm using $.map() to convert the array of channel IDs into an array of promises for each ID. After that, I have a simple helper function with handles the normal response (res), pulls out the relevant stream data, while attaching the channelId for use later on. (Without this, we would have to go back to the original array to get the ID. You can do this, but in my opinion, that isn't the best practice. I'd much prefer to keep the data with the response so that later refactoring is less likely to break something. This is a matter of preference.)
Next, I have a .then() handler which takes all of the data and loops through them. This data is returned as arguments to the function, so I simply use $.each() to iterate over each argument rather than having to name them out.
I made some changes in how I'm handling the HTML as well. You'll note that I'm using $.text() and $.attr() to set the dynamic values. This ensures that your HTML is valid (as you're not really using HTML for the dynamic bit at all). Otherwise, someone might have the username of <script src="somethingEvil.js"></script> and it'd run on your page. This avoids that problem entirely.
It looks like you're appending the "Display Name" in the same order every time you refresh, by using the j counter variable.
However, you're appending the "Status" as each request returns. Since these HTTP requests are asynchronous, the order in which they are appended to the document will vary each time you reload the page.
If you want the statuses to remain in the same order (matching the order of the Display Names), you'll need to store the response data from each API call as they return, and order it yourself before appending it to the body.
At first, I changed the last else condition (the one that prints out the streamed game) as $(".stat").append("<li>"+jtw[j]+": "+json.stream.game+"</li>"); - it was identical in meaning to what you tried to achieve, yet produced the same error.
There's a discrepancy in the list you've created and the data you receive. They are not directly associated.
It is a preferred way to use $(".stat").append("<li>"+json.stream._links.self+": "+json.stream.game+"</li>");, you may even get the name of the user with regex or substr in the worst case.
As long as you don't run separate loops for uploading the columns "DisplayName" and "Status", you might even be able to separate them, in case you do not desire to write them into the same line, as my example does.
Whatever way you're choosing, in the end, the problem is that the "Status" column's order of uploading is not identical to the one you're doing in "Status Name".
This code will not preserve the order, but will preserve which array entry is being processed
$(document).ready(function() {
var ur = "";
var tw = ["freecodecamp", "nightblue3", "imaqtpie", "bunnyfufuu", "mushisgosu", "tsm_dyrus", "esl_sc2"];
for (var i = 0; i < tw.length; i++) {
ur = "https://api.twitch.tv/kraken/streams/" + tw[i];
(function(j) {
$.getJSON(ur, function(json) {
$(".tst").append(JSON.stringify(json));
$(".name").append("<li> " + tw[j] + "<p>" + "" + "</p></li>");
if (json.stream == null) {
$(".stat").append("<li>" + "Offline" + "</li>");
} else {
$(".stat").append("<li>" + json.stream.game + "</li>");
}
})
}(i));
}
});
This code will preserve the order fully - the layout needs tweaking though
$(document).ready(function() {
var ur = "";
var tw = ["freecodecamp", "nightblue3", "imaqtpie", "bunnyfufuu", "mushisgosu", "tsm_dyrus", "esl_sc2"];
for (var i = 0; i < tw.length; i++) {
ur = "https://api.twitch.tv/kraken/streams/" + tw[i];
(function(j) {
var name = $(".name").append("<li> " + tw[j] + "<p>" + "" + "</p></li>");
var stat = $(".stat").append("<li></li>")[0].lastElementChild;
console.log(stat);
$.getJSON(ur, function(json) {
$(".tst").append(JSON.stringify(json));
if (json.stream == null) {
$(stat).text("Offline");
} else {
$(stat).text(json.stream.game);
}
}).then(function(e) {
console.log(e);
}, function(e) {
console.error(e);
});
}(i));
}
});

Que functions and execute after animation is complete

I am using SignalR to update my web app in real time based on operations taking place on the server. Right now I am incrementing a counter eachtime a record is saved in the database. I want the span holding the counter number to fade out, change, then fade back in. The only issue here is the method can be called several times within the time it takes to complete a fade out. My current code looks like this.
var todaysRequests = "";
var todayElement = $('#todays-requests');
//check if element is currently being animated, if so, just change the span text. If not then
//initiate the animation then change the span text
if ($(todayElement).is(':animated')) {
todaysRequests = parseInt($('#todays-requests').text());
todaysRequests++;
$(todayElement).text(todaysRequests.toString());
} else {
$(todayElement).fadeOut(300, function () {
//at this point its possible another call was made to this method and the counter was
//incremented. We need to get the counter number again just incase it has been incremented
//then we can actually increment it.
todaysRequests = parseInt($('#todays-requests').text());
todaysRequests++;
$(todayElement).text(todaysRequests.toString());
$(todayElement).fadeIn(300);
});
}
The problem is there's no way to persist data in between calls to the above function. I thought about using local storage to store an integer that gets incremented each time this function gets run while the span is still being animated, then in the animation finish check local storage and adjust the counter. This could work but it seems like too much work. There has to be a more elegant solution. Right now it doesn't look so bad but if more than one call to the function is made you can see the span incrementing as it is fading out.
Update
Checking into jquery.queue(). It looks like you can que functions to an element to be called after something else happens. I'm not 100% sure how to que them and then have them execute only after animation is complete.
Try
var todayElement = $("#todays-requests")
, data = 0;
$.when(todayElement.queue("fx", function () {
todayElement.fadeOut(300, function () {
todayElement.text(data)
}).fadeIn(300)
}).dequeue("fx"))
.promise("fx", todayElement)
.done(function (el) {
console.log(data + " tasks complete"
, "queue length: " + el.queue("fx").length)
})
var todayElement = $("#todays-requests"),
data = 0;
var request = function (d, t) {
setTimeout(function () {
$.get("https://gist.githubusercontent.com/anonymous/ca95080f6d3a7b32bb95/raw/120dec0dce825193b0551ad1fbda4b71029b336d/js.js")
.done(function (n) {
++data
})
}, t)
};
for (var i = 0; i < 100; ++i) {
request(i, i * 275)
}
$(document).on("ajaxStop", function (e) {
$.when(todayElement.queue("fx", function () {
todayElement.fadeOut(300, function () {
todayElement.text(data)
}).fadeIn(300)
}).dequeue("fx"))
.promise("fx", todayElement)
.done(function (el) {
console.log(data + " tasks complete"
, "queue length: " + el.queue("fx").length)
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="todays-requests"></div>

Array is empty outside the function, trying to fetch data from database, in Javascript

I'm trying to build an application with Ionic Framework and Javascript, and I want to fetch all the data from a table in an array, but when I try to access that array outside the function it's empty. I've read something that maybe the array gets populated after the console.log("length "+ $scope.cards.length); but I don't know how to solve this so I can use the array after that.
This is the function for fetching the data from the table(it works):
fetchCards: function(success) {
database.transaction(function(tx) {
tx.executeSql("SELECT cardId, name, chosen, filePath, found FROM Cards", [],
function (tx, results) {
console.log('success select ' + results);
cards = [];
for (i = 0; i < results.rows.length; i++) {
cards.push(results.rows.item(i));
}
success(cards);
},
function () {
console.log('error select');
});
});
}
This is where I try to access the array, in a controller:
.controller('kindergartenController', function($scope, $ionicSideMenuDelegate,service) {
//list with the difficulties
$scope.difficultyList=[
{text:"Easy", value:"easy"},
{text:"Medium", value:"medium"},
{text:"Hard", value:"hard"}];
$scope.data={difficulty:''};
//redirecting if it presses
$scope.goToAnimalsGame = function() {
if($scope.data.difficulty=='easy'){
window.location = "#/menu/animalseasy";
//in this array I want the results
$scope.cards=[];
game = new Game(1,"easyAnimalGame");
console.log("created a new game " + game.getName());
game.createMemoryGame();
console.log("difficulty " + $scope.data.difficulty);
randomNumbers=game.randomNumbers($scope.data.difficulty);
console.log('Random numbers are:');
for(i=0;i<randomNumbers.length;i++){
console.log(randomNumbers[i]);
}
//here is where I call the other function, to get data from database
service.fetchCards(function(cards) {
$scope.cards = cards;
//it shows the good length
console.log("length "+ $scope.cards.length);
});
//it shows it's empty
console.log("length "+ $scope.cards.length);
}
Any suggestions are helpful, thank you.
It will show empty because:
service.fetchCards
is Asynchronous, therefore inside that function where you define your anonymous callback, won't fire till the data is retrieved.
the console.log("length ".... outside of the function will be executed immediately after the function call fetchCards, but possibly before the callback where the array gets populated.
Unfortunately you can only deal with the populated array within the callback or from a function fired within the callback.
Here is a timeline of execution to aid:
service.fetchCards();
->
console.log("length "....) below the above function
->
anonymous callback (function (cards){}) inside the service.fetchCards()
If that makes sense.
The asynchronism of the service means that the callback you defined anonymously could fire at any time.
The solution:
service.fecthCards(function (data) {
// do your code
$scope.cards = cards;
//it shows the good length
console.log("length "+ $scope.cards.length);
// manipulate the array within this function or get it to call another function like so
nowContinue();
});
function nowContinue() {
// continue what ever it was that you wanted to do using the newly populated information
}
Because nowContinue is called with in the anonymous callback it will fire whenever the callback gets fired, and will execute after you have populated the controllers local variables with data.

How to get rating star value from mysql?

In my Worklight-based application, I have a rating value(int) stored in mysql. I have as JSON data the rating integer value.
{"storeId":1000,"zipcode":"600014","rating":3,}
Using Jquery I need to display that rating value as images of stars in the application.
If the value is 2, then I need to display 2 star images, and so on.
How can I accomplish this?
It would've been helpful to see what you've implemented thus far (adapter implementation, client-side adapter invocation, ...).
Without it, I can only provide one possible way to get a value from from a database and display it.
It is assumed that:
In your database, there is a 'stars' field and value
In the common\images folder in your application, there is an image of a star
You have created a SQL adapter and configured it correctly
Implementation:
In common\index.html there is, for example, an empty UL element just so that the fetched data will be in a list:
<ul id="usersAndStars"></ul>
In common\js\main.js, you invoke your adapter:
// Of course, you can invoke it whenever you actually want to, and not like below...
function wlCommonInit(){
getStarsFromDatabase();
}
function getStarsFromDatabase() {
var invocationData = {
adapter: 'getStars',
procedure: 'getStars'
};
WL.Client.invokeProcedure(
invocationData,
{
onSuccess: displayStars,
onFailure: failedGettingStars
});
}
Then you handle the response of the invocation, failure and success:
function failedGettingStars() {
alert("failure");
}
function displayStars(response) {
var ul = $('#usersAndStars');
var i, j, li;
for (i = 0; i < response.invocationResult.resultSet.length; i += 1) {
// Create new <li> element and populate it
li = $("<li/>").text("Item " + [i+1] + " has " + response.invocationResult.resultSet[i].stars + " stars: ");
// Add images of a star
// Note that this is purely applicative - instead of adding several img tags,
// You could simply add an image showing 5 or 2 or 3 or however stars you want...
// Or in any other way you want.
for (j = 0; j < response.invocationResult.resultSet[i].stars; j += 1) {
li.append("<img src='images/\star.png' alt='star'/>");
}
// Append the <li> element to the <ul> element
ul.append(li);
};
}
In adapters\getStars\getStars-impl.js file:
var selectStatement = WL.Server.createSQLStatement("select * from users");
function getStars() {
return WL.Server.invokeSQLStatement({
preparedStatement : selectStatement,
parameters : []
});
}
In adapters\getStars\getStars.xml file:
...
...
...
<procedure name="getStars"/>
The end result:

Categories