I'm trying to put the data read from the database in a variable. I have tryed many things, including a callback function, but nothing looks to work when the process is outside of the "opencursor().onsuccess" function scope.
The "Alert 1" show the result correctly, but "Alert 2" and "Alert 3" don't.
I'm calling the 'main()' function from HTML code.
I'm really frustrated, because I have been mining internet searching for the solution without any positive result.
Can anybody help me, please?
Thanks a lot.
var data=[];
function kkeyget(t1, db_name, db_version)
{
var request = indexedDB.open(db_name, db_version);
request.onerror=function()
{
alert("Error");
}
request.onsuccess=function(event)
{
var db=this.result;
var trans = db.transaction(t1, "readonly");
var objectStore = trans.objectStore(t1);
objectStore.openCursor().onsuccess = function(event)
{
var cursor = event.target.result;
if (cursor)
{
data.push(cursor.value);
//Alert 1:
alert(data[0].id);
cursor.continue();
}
else alert("No more entries!");
};
}
//Alert 2:
alert(data[0].id);
}
function main()
{
kkeyget("agenda", "example_db", 1);
//Alert 3:
alert(data[0].id);
}
Correct. Because all indexedDB actions are asynchronous, your code will run:
alert 2 // undefined
alert 3 // undefined
alert 1 // correct
In order to get this closer to a synchronous action, you need to have it call a new function after it's done collecting data. Where your alert("No more entries!") is.
Instead of trying to return a key, pass in a custom callback function that takes the retrieved key as its argument.
// Your old function slightly modified
function kkeyget(t1, db_name, db_version, callback, fallback) {
// ... yada yada yada
objectStore.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if(cursor) {
callback(cursor.value);
} else {
fallback();
}
}
}
// Now in your calling code:
kkeyget('a','b',1, function(id) {
// Do something with the 'id'
// here in this anonymous function callback
}, function() {
// Do something here to indicate no match
});
Related
I need to do some API call and also DB manipulation during rendering of messages for a function.
I have these long function, let's call it alongFunction
function longFunction(message, item) {
var win = lib.gui.window.get(id);
var msg = message.msg;
var id = message.id;
var direction = message.direction;
//inside are basically some DOM manipulation
//around 10 lines here
//and also there are rendering/misc code
//around 10 lines here
//then we are rendering some messages here:
var msgDiv = $('<div>'), msgTsDiv = $('<div>');
msgDiv.addClass('chat '+direction);
msgDiv.attr('id', id);
if(direction == 'in') {
//I need to add a hook here to do API call, but it takes some time
msgDiv.html('<div class="message in">'+message+'</div>');
} else {
msgDiv.html('<div class="message out">'+message+'</div>');
}
//NEW CODE ADDED HERE: Check below pls
//and because JS is async, it just passes these codes
//around 50 codes for manipulation etc...
if(message.isReceived()) {
msgDiv.addClass('received');
}
//and some other stuff here...
}
I added at the NEW CODED ADDED HERE these:
function longFunction(message, item) {
var win = lib.gui.window.get(id);
var msg = message.msg;
var id = message.id;
var direction = message.direction;
//inside are basically some DOM manipulation
//around 10 lines here
//and also there are rendering/misc code
//around 10 lines here
//then we are rendering some messages here:
var msgDiv = $('<div>'), msgTsDiv = $('<div>');
msgDiv.addClass('chat');
msgDiv.attr('id', id);
//only translating message coming in
if(direction == 'in') {
getTranslatedMessage(message).then(function(newMessage){
//I need to add a hook here to do API call, but it takes some time
msgDiv.html('<div class="message in">'+newMessage+'</div>');
}).catch(function(error){
if(error) {
msgDiv.html('<div class="message">'+message+'<br>'+error+'</div>');
} else {
msgDiv.html('<div class="message in">'+message+'</div>');
}
});
} else {
msgDiv.html('<div class="message out">'+message+'</div>');
}
//end of translation - UPDATE
//and because JS is async, it just pass these codes
//around 50 codes for manipulation etc...
if(message.isReceived()) {
msgDiv.addClass('received');
}
//and some other stuff here...
}
UPDATE:
I have tried
putting everything into one big callback = but it is not returning any result.
repeat the remaining code by copy-pasting it into the callback and outside = the message printed is not in proper sequence (this function is called in a loop)
Note: The function is a bit long, so I just made a simple version for it
Important: This function is being called in a loop.
Thank you in advance!
So I am trying to write javascript code for a ribbon button in Dynamics CRM 2016 that will grab a phone number from a list of Leads that can be seen in the Active Leads window.
However, when I try to run it, I get an error telling me
As I step into my code (I'm debugging), I see this error
Here is the code I am working with.
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
// this should iterate through the list
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
//this should get the id and name of the selected lead
getPhoneNumber(selected, SelectedEntityTypeName);
});
}
//I should have the lead ID and Name here, but it is returning null
function getPhoneNumber(id, entityName) {
var query = "telephone1";
Sdk.WebApi.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
// I'm trying to capture the number and display it via alert.
alert(telephone1);
},
function (error) {
alert(error);
})
}
Any help is appreciated.
What you have is an javascript error. In js you can only use forEach on an array. SelectedControlSelectedItemIds is an object not an array.
To loop though an object, you can do the following.
for (var key in SelectedControlSelectedItemIds){
if(SelectedControlSelectedItemIds.hasOwnProperty(key)){
getPhoneNumber(SelectedControlSelectedItemIds[key], SelectedEntityTypeName)
}
}
Okay, so I figured it out. I had help, so I refuse to take full credit.
First, I had to download the SDK.WEBAPI.
I then had to add the webAPI to my Javascript Actions in the Ribbon Tool Bench.
Then, I had to create a function to remove the brackets around the
SelectedControlSelectedItemIds
Firstly, I had to use the API WITH the forEach method in order for it to work.
These are the revisions to my code.
function removeBraces(str) {
str = str.replace(/[{}]/g, "");
return str;
}
function updateSelected(SelectedControlSelectedItemIds, SelectedEntityTypeName) {
//alert(SelectedEntityTypeName);
SelectedControlSelectedItemIds.forEach(
function (selected, index) {
getPhoneNumber(removeBraces(selected), SelectedEntityTypeName);
// alert(selected);
});
}
function getPhoneNumber(id, entityName) {
var query = "telephone1";
SDK.WEBAPI.retrieveRecord(id, entityName, query, "",
function (result) {
var telephone1 = result.telephone1;
formatted = telephone1.replace(/[- )(]/g,'');
dialready = "1" + formatted;
withcolon = dialready.replace(/(.{1})/g,"$1:")
number = telephone1;
if (Xrm.Page.context.getUserName() == "Jerry Ryback") {
url = "http://111.222.333.444/cgi-bin/api-send_key";
} else if(Xrm.Page.context.getUserName() == "Frank Jane") {
url = "http://222.333.444.555/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bob Gilfred"){
url = "http://333.444.555.666/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Cheryl Bradley"){
url = "http://444.555.666.777/cgi-bin/api-send_key";
}
else if( Xrm.Page.context.getUserName() == "Bill Dunny"){
url = "http://555.666.777.888/cgi-bin/api-send_key";
}
if (url != "") {
var params = "passcode=admin&keys=" + withcolon + "SEND";
var http = new XMLHttpRequest();
http.open("GET", url + "?" + params, true);
http.onreadystatechange = function () {
if (http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.send(null);
}
},
function (error) {
// alert(error);
})
}
To elaborate, once I successfully get the number, I remove the parenthesis, dashes and white-space. Then, I add a "1" to the beginning. Finally, I insert colons in between each number. Then, I create an HTTP command and send it to the office phone of whoever is using CRM at the time. The user eval and HTTP message is my code. I'm showing you all of this because it was a great learning experience, and this feature really adds to the functionality.
I hope some of you find this useful.
Thanks for the help.
I am attempting to test multiple sites for section headers being in the correct order. Of course everything is asynchronous in Nightwatch, including getting text from an element. The following code leads to the timeout never being called.
client.url(`www.oneofmyrealestatesites.com`);
client.waitForElementPresent("body", 5000);
var _ = require("underscore");
// This is the order I expect things to be in
var expected = ["Homes For Sale", "New Homes", "Apartments & Rentals"];
client.elements("css selector", ".listings .module-title .label", function (data) {
var listings = [];
data.value.forEach(function (element) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
})
})
setTimeout(function () {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
}, 5000);
});
It would appear that no matter how much delay I give, listings is ALWAYS empty. If I console.log listings as it's being pushed to, it is getting populated, so that's not the issue. client.pause is always ignored as well.
Is there a way to make sure that listings is populated before asserting the diff?
I'm using async library for such cases https://github.com/caolan/async
Docs: https://github.com/caolan/async/blob/v1.5.2/README.md
var async = require("async");
/*use each, eachSeries or eachLimit - check docs for differences */
async.eachSeries(data.value, function (element, cb) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
// this job is done
cb();
});
}, function() {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
});
setTimeout can only be called from .execute or .executeAsync because its actual javascript. The function below was only working until I used .executeAsync
Hope this works for you.
Cheers, Rody
LoopQuestionsLogSymptom: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium, false);
this.api.executeAsync(function() {
let checkQuestion = function() {
// GET THE ELEMENTS
let nextButton = document.querySelectorAll('.next-button');
let answers = document.getElementsByClassName('flex-row');
let blueButton = document.querySelector('.blue-inverse-button');
let doneButton = document.querySelector('#doneButton');
let monitor = document.querySelector('.monitor');
//CHECK THE TYPES OF QUESTIONS AND CLICK THE RIGHT BUTTONS
if (!blueButton) {
answers[0].click();
nextButton[0].click()
} else if(blueButton){
blueButton.click();
}
setTimeout(() => {
if(!doneButton) {
console.log('Answering another question!');
checkQuestion();
}
if(doneButton){
doneButton.click();
}
else if(monitor) {
console.log("Exiting?")
.assert(monitor);
return this;
}
}, 2000);
};
// Initiating the check question function
return checkQuestion();
},[], function(){
console.log('Done?')
});
this.waitForElementVisible('.monitor', constants.timeout.medium);
this.assert.elementPresent('.monitor');
this.assert.urlEquals('https://member-portal.env-dev4.vivantehealth.org/progress');
return this;
},
Hey 2 questions within this post, they are probably simple for you experienced js guys :-)
First; why is "filename" undefined inside the readEntries when I pass it along?
Second; Why is it always true, when the directory is empty?
Heres my code: I'm calling getPicturepath with a string like "women.png".
function getPicturePath(filename){
alert(filename); //is correct
var reader = DATADIR.createReader();
reader.readEntries(function(entries, filename){
alert(filename);//is undefined ???
var doWeHaveIt = function(entries,filename){
checkForFile(entries,filename)
};
if(doWeHaveIt){
alert('allready have: '+DATADIR.fullPath+filename);
} else {
alert('need to download file: '+filename);
}
},onError);
}
function checkForFile(entries,filename){
console.log("The dir has "+entries.length+" entries.");
if(entries.indexOf(filename)!=-1){
alert(filename+' allready exists');
return true;
} else {
alert(filename+" doesn't exists");
return false;
}
}
reader.readEntries(function(entries, filename){
This is the function defining the parameters entries and filename.
For example, this function might do something like:
readEntries: function( callback ) {
// do something, then
callback( some, datas );
}
If you just want to use filename in this function, just use it. Like this:
function getPicturePath(filename){
alert(filename); //is correct
var reader = DATADIR.createReader();
reader.readEntries(function(entries){
alert(filename);// is still correct
The second part (always true) is because of this:
function hi() {}
if ( hi ) {
// You're always getting there.
}
What I wrote is exactly what you did. I let you guess how to correct that :-)
SOLVED.
I changed my code into this:
function init() {
//preloadImages();
getContent('events', 'events');
getContent('content', 'main');
}
function loadingScreen(start) {
var loadingSpan = document.getElementById('loading');
if (start == true) {
loadingSpan.innerHTML = '<p>Loading...<br><img src="images/loading.gif"></p>';
}
else {
loadingSpan.innerHTML = '';
}
}
function getContent(what, where) {
if (what == 'content') {
loadingScreen(true);
var ranLoad = true;
}
var toSet = document.getElementById(what);
var location = "content/" + where + ".txt";
var request = new XMLHttpRequest;
request.open("GET", location, true);
request.onreadystatechange = function(){
if (request.readyState == 4 && request.status == 200){
toSet.innerHTML = request.responseText;
if (ranLoad==true){
loadingScreen(false);
}
}
}
request.send(null);
}
window.onload = init;
tl;dr or long-winded - see the code and the results below.
So. I am building a small webpage for a friend, and I decided to try out a technique where instead of writing the content directly in the webpage, I will use XMLHttpRequest to retrieve content (in the same domain), and place them in the content , where it will be updated by javascript, when people click on a different anchor.
Well, I came across a roadbump.
When I created the functions for getting the content (setEvents and setContent), where it creates a variable and calls a function for setting the variable (getMarkup), when the function was called, and the return statement was executed, it returns undefined. I found a thread similar, but their solution was to add the innerHTML statement DIRECTLY in the getMarkup function. I don't want to do that.
Here's the code and the results:
Edit: Esailija suggested that I should have just posted the code. To me it was a tad bit easier to just take the image, but here it is:
function init() {
//preloadImages();
setEvents();
setContent('main');
}
function setEvents() {
var eventDiv = document.getElementById("events");
var eventContent = getMarkup("content/events.txt");
eventDiv.innerHTML = eventContent;
}
function setContent(which) {
loadingScreen('start');
var contentDiv = document.getElementById('content');
location_ = "content/" + which + 'txt';
//var contentContent = getMarkup('location');
//contentDiv.innerHTML = contentContent;
loadingScreen('stop');
}
function loadingScreen(action) {
var loadingSpan = document.getElementById('loading');
loadingSpan.innerHTML = "Test";
if (action == 'start') {
loadingSpan.innerHTML = '<p>Loading...<br><img src="images/loading.gif"></p>';
}
if (action == 'stop') {
loadingSpan.innerHTML = '';
}
}
function getMarkup(where) {
var filerequest = new XMLHttpRequest();
filerequest.open("GET", where, true);
filerequest.onreadystatechange = function() {
if (filerequest.readyState == 4 && filerequest.status == 200) {
var test = document.getElementById("events");
var reply = filerequest.responseText;
//Doesn't work
return reply;
//Works just fine
//test.innerHTML = reply;
}
};
filerequest.send(null);
}
window.onload = init;
When I do the innerHTML instead of return it shows "Test TEST", and when I do return instead of innerHTML, it shown "undefined".
I really don't want to do the innerHTML part of it, so is there a workaround to make that return statement work?
Are you familiar with callbacks? Open up Firebug and put a breakpoint on your return reply; line - notice the call stack. The function where you have return reply; is not getMarkup.
Basically you're going to have to restructure your code a little. I would have getMarkup take an additional parameter - the DOM element to which you want to set its innerHTML value.
It seems that you don't quite understand how ajax works.
Once you call your getMarkup function, you send an ajax request and tell the browser to use the function after onreadystatechange to handle the reply. So actually when the reply is back, it's not your other functions like setContent that are calling that handler but the browser. That's why the return doesn't work.
Also when you call something like var contentContent = getMarkup('location'); , as getMarkup has no explicit return value, so by default contentContent gets undefined. You may think that it should get the return value inside your anonymous function but that's not the case. The getMarkup function returns immediately but the handler will be called only when the ajax response comes.
If you want to make that nice, you will have to do something extra like: you only have one ajax handler like you did. Once a function called that ajax function it register its callback into a queue and when the response is back the queue is popped and the values are then updated. This would take some time for you to build this mechanism or you may need to check how the jQuery Ajax Queue works.