i am trying to get a pagenumber values from the method getPageNumber(), where the page number is getting printed in console. But that value is not used in While loop. Even if i try to print pageNum, it returns promise.
Refer console output.
it('TS-06, should able to navigate to Manage Users Screen',function(){
clientAdminPortal.clickMenuInSideBar("User Management");
manageUsers.at().then(function() {
console.log("---> Navigated to Manage Users Screen");
});
expect(manageUsers.isVisible(manageUsers.searchTxtBox)).toBeTruthy();
});
it('TS-10, verify Activate Button is viewed for all users',function(){
var i=1;
var check=false;
var pageNum=manageUsers.getPageNumber();
while(i<pageNum){
console.log("check");
i++;
}
});
this.getPageNumber=function(){
return this.pgnumCount.then(function(number){
console.log(number.length);
return number.length;
});
};
Because this.getPageNumber() return a promise, you have to consume promise within then() as below:
it('TS-10, verify Activate Button is viewed for all users', function () {
var i = 1;
var check = false;
manageUsers.getPageNumber().then(function (pageNum) {
while (i < pageNum) {
console.log("check");
i++;
}
});
});
Related
I'm creating a var where I want to assign it to a var that I get from another entity
function SubmitAction(executionContext) {
var lookupItem = formContext.getAttribute("alfa_member").getValue()[0].id;
var theTotalMembersTravling = formContext.getAttribute("alfa_numberofdependent").getValue();
var remainFlightCredit;
debugger;
Xrm.WebApi.online.retrieveRecord("contact",lookupItem, "?$select=new_remainstravelcredit").then(
function employessPackage(result) {
var new_remainstravelcredit = result["new_remainstravelcredit"];
if(new_remainstravelcredit !== null){
if(new_remainstravelcredit > 0)
{
remainFlightCredit = new_remainstravelcredit;
console.log(remainFlightCredit+" This not inside any if condition");
var newRemain = (parseInt(remainFlightCredit)) - (parseInt(theTotalMembersTravling));
console.log(newRemain+ " This in the remain if condition");
var entity = {};
entity.new_remainstravelcredit = newRemain.toString();
Xrm.WebApi.online.updateRecord("contact",lookupItem, entity).then(
function success(result) {
var updatedEntityId = result.id;
},
function(error) {
Xrm.Utility.alertDialog(error.message);
}
);
} if(new_remainstravelcredit <= 0)
{
Xrm.Utility.alertDialog("You have exceeds the travel credit");
console.log(remainFlightCredit);
}
}
},
function(error) {
Xrm.Utility.alertDialog(error.message);
}
);
console.log(remainFlightCredit);
}
So as result in this line
remainFlightCredit = new_remainstravelcredit;
console.log(remainFlightCredit+" This not inside any if condition");
Which inside the webapi call I'm able to get the value but outside in the main function at the end when I write
console.log(remainFlightCredit);
I'm unable to get the value remainFlightCredit, do you have any suggestions to solve this issue?
This is expected behavior, as this is a promise call (asynchronous) the code outside the main api call will execute before the success callback function employessPackage.
So remainFlightCredit value get assigned after the last console.log line in your code.
You can place a breakpoint to debug and see it in action.
I've been scouring similar problems but haven't seem to have found a solution that quite works on my end. So I'm working on a Discord bot that takes data from a MongoDB database and displays said data in the form of a discord embedded message using Mongoose. For the most part, everything is working fine, however one little section of my code is giving me trouble.
So I need to import an array of both all available users and the "time" data of each of those users. Here is the block of code I use to import said data:
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
Now this for loop references a function I made called getData which obtains the data from MongoDB by this method:
async function getData(field, value){
var data;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
data = result[value];
}
});
if(field == "user"){
return data.user;
}else if (field == "time"){
return data.time;
}else{
return 0;
}
So that for loop is where my errors currently lie. When I try to run this code and display my data through a discord message, I get this error and the message does not get sent:
(node:13936) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'time' of undefined
Now the strange thing is, this error does not happen every time. If I continue calling the command that triggers this code from my discord server, it's almost like a 50/50 shot if the command actually shows the message or instead gives this error. It is very inconsistent.
This error is confounding me, as the undefined part does not make sense to me. The objects that are being searched for in the mongoDB collection are definitely defined, and the for loop never exceeds the number of objects present. My only conclusion is that I'm doing something wrong with my asynchronous function design. I have tried altering code to use the getData function less often, or to not use awaits or asynchronous design at all, however this leaves my final discord message with several undefined variables and an eventual crash.
If anyone has any advice or suggestions, that would be very much appreciated. Just for reference, here is the full function that receives the data, sorts it, and prepares a string to be displayed on the discord server (though the error only seems to occur in the first for loop):
async function buildString(){
var string = "";
var totalObj;
var timeArray = [];
var userArray = [];
var stopSort = false;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
totalObj = result.length;
}
});
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
while(!stopSort){
var keepSorting = false;
for(i = 0; i < totalObj ; i++){
var target = await convertTime(timeArray[i]);
for(j = i + 1 ; j < totalObj ; j++){
var comparison = await convertTime(timeArray[j]);
if(target > comparison){
//Switch target time with comparison time so that the lower time is up front
var temp = timeArray[i];
timeArray[i] = timeArray[j];
timeArray[j] = temp;
//Then switch the users around so that the user always corresponds with their time
var userTemp = userArray[i];
userArray[i] = userArray[j];
userArray[j] = userTemp;
//The loop will continue if even a single switch is made
keepSorting = true;
}
}
}
if(!keepSorting){
stopSort = true;
}
}
//String building starts here
var placeArray = [':first_place: **1st', ':second_place: **2nd', ':third_place: **3rd', '**4th', '**5th', '**6th', '**7th', '**8th', '**9th', '**10th'];
for(i = 0; i < totalObj; i++){
string = await string.concat(placeArray[i] + ": " + userArray[i] + "** - " + timeArray[i] + " \n\n");
console.log('butt');
}
console.log("This String:" + string);
return string;
}
I think problem is you are trying to await function with callback, it will not work => access to data.time may run before data = result[value]. If you need await callback, you can use custom Promise (or use util.promisify, more info here)
Promise:
function findStats(options) {
return new Promise((resolve, reject) => {
return stats.find(options, function (err, result) {
if (err) {
return reject(err)
}
return resolve(result)
})
})
}
utils.promisify
const util = require('util');
const findStats = util.promisify(stats.find);
Now you can use await in your function
async function getData(field, value) {
try {
const result = await findStats({})
const data = result.value
if (field === 'user') {
return data.user
}
if (field === 'time') {
return data.time
}
return 0
} catch (error) {
// here process error the way you like
// or remove try-catch block and sanitize error in your wrap function
}
}
I use the recursive function below, in order to reopen website if httpstatus != 200:
retryOpen = function(){
this.thenOpen("http://www.mywebsite.com", function(response){
utils.dump(response.status);
var httpstatus = response.status;
if(httpstatus != 200){
this.echo("FAILED GET WEBSITE, RETRY");
this.then(retryOpen);
} else{
var thisnow = hello[variable];
this.evaluate(function(valueOptionSelect){
$('select#the_id').val(valueOptionSelect);
$('select#the_id').trigger('change');
},thisnow);
}
});
}
The problem is that sometimes the retryOpen function does not even go as far as to callback function(response){}. Then, my script freezes.
I wonder how one could change the function to be able to recursively try to open website again if there is no response from website (not even some error code as 404 or something)? In other words, how to rewrite the retryOpen function so it reruns when the function does not reach callback after a certain amount of time?
I would try something like this. Please note this is untested code, but should get you on the correct path
retryOpen = function(maxretry){
var count = 0;
function makeCall(url)
{
this.thenOpen(url, function(response){
utils.dump(response.status);
});
}
function openIt(){
makeCall.call(this,"http://www.mywebsite.com");
this.waitFor(function check() {
var res = this.status(false);
return res.currentHTTPStatus === 200;
}, function then() {
var thisnow = hello[variable];
this.evaluate(function(valueOptionSelect){
$('select#the_id').val(valueOptionSelect);
$('select#the_id').trigger('change');
},thisnow);
}, function timeout() { // step to execute if check has failed
if(count < maxretry)
{
openIt.call(this);
}
count++
},
1000 //wait 1 sec
);
}
openIt();
}
I have the following code which is working except for the $.when.apply($, promises).done() function (I have console logging showing when things are being processed).
I don't understand why the .done is not functioning.
What the code is basically doing is for each select in a filter container populate the select with values form an indexed db which is its own function and returns a promise. I can see everything working but the final .done is supposed to display items on the screen when everything has rendered, however the screen elements do not show and the page stays white.
grid.genPage = function() {
console.time('genPage');
$(grid.settings.filterContainer).hide();
var gridParent = grid.e.parent('div');
gridParent.hide();
var promises = [];
return $.Deferred(function(){
var self = this;
if (!grid.settings.startGenPage.call(this, grid)){
self.reject();
}
grid.dtOptions.oColVis.aiExclude = [0];
grid.displayFields = [];
$.when(
grid.buildFilter(),
grid.buildViews(),
grid.generateDataTable(grid.showColumns),
grid.buildManageButtons()
).then(function(){
console.log('start populating filters');
$.each(grid.config.configs[grid.settings.defaultView], function(i, v) {
var p = $.Deferred(function(){
var self = this;
var field = Object.keys(v); //get field Name
if ($.inArray(i, grid.configIgnorArray) > -1) {
console.log('ignore resolve');
self.resolve();
}
var c = v[field];
if (c.filters.fieldType === 'select') {
var el = $('select[name="' + grid.e.prop('id') + 'Filter_' + field + '"]');
var os = c.options.objectStore;
var idx = c.options.idx;
var s = c.options.lookup;
$.when(grid.checkCache(el, c.options.objectStore, c.options.idx, c.options.lookup))
.then(function(){
console.log('select resolve');
self.resolve();
});
}else {
console.log('other resolve');
self.resolve();
}
});
promises.push(p);
});
});
}).then(function(){
$.when.apply($, promises).then(function(){
console.log('end populating filters');
console.log('genpage finish');
grid.settings.completeGenPage.call(this, grid);
$(grid.settings.filterContainer).show();
gridParent.show();
console.timeEnd('genPage');
self.resolve();
});
}).promise();
};
In the above code the console.log('end populating filters'); never appear in the console. I am sure it's an issue with something not resolving correctly but I cannot see where.
Thanks in advance
You need to resolve the first deferred object in order to fire the then() success callback:
self.resolve();
I'm making a little app that displays a list of the top first song of an artist's related artists. When I try and load my app for the first time, it shows nothing. But, when I "Reload Application" everything seems to work. When I constantly start "Reloading" it keeps adding more of the same tracks to the list as well.
How do I stop it from continually appending more tracks to the list as well as tighten up the code so that it works on load?
require([
'$api/models',
'$views/list#List',
'$api/toplists#Toplist'
], function(models, List, Toplist){
'use strict';
// Build playlist
function buildList(trackURIArray){
var arr = trackURIArray;
models.Playlist
.createTemporary("myTempList")
.done(function(playlist){
playlist.load("tracks").done(function(loadedPlaylist){
for(var i = 0; i < arr.length; i++){
loadedPlaylist.tracks.add(models.Track.fromURI(arr[i]));
}
});
// Create list
var list = List.forPlaylist(playlist,{
style:'rounded'
});
$('#playlistContainer').append(list.node);
list.init();
});
}
// Get top track
function getTopTrack(artist, num, callback){
var artistTopList = Toplist.forArtist(artist);
artistTopList.tracks.snapshot(0, num).done(function (snapshot){
snapshot.loadAll('name').done(function(tracks){
var i, num_toptracks;
num_toptracks = num;
for(i = 0; i < num_toptracks; i++){
callback(artist, tracks[i]);
}
});
});
}
// Get Related
function getRelated(artist_uri){
var artist_properties = ['name', 'popularity', 'related', 'uri'];
models.Artist
.fromURI(artist_uri)
.load(artist_properties)
.done(function (artist){
artist.related.snapshot().done(function(snapshot){
snapshot.loadAll('name').done(function(artists){
var temp = [];
for(var i = 0; i < artists.length; i++){
getTopTrack(artists[i], 1, function(artist, toptrack){
var p, n, u;
p = artist.popularity;
n = artist.name;
u = artist.uri;
temp.push(toptrack.uri);
});
}
// Build a list of these tracks
buildList(temp);
});
});
});
}
getRelated('spotify:artist:2VAvhf61GgLYmC6C8anyX1');
});
By using Promises you can delay the rendering of the list until you have successfully composed the temporary list with your tracks. Also, in order to prevent the addition of repeated tracks on reload, assign a unique name to your temporary playlist.
require([
'$api/models',
'$views/list#List',
'$api/toplists#Toplist'
], function (models, List, Toplist) {
'use strict';
// Build playlist
function buildList(trackURIArray) {
var arr = trackURIArray;
models.Playlist
.createTemporary("myTempList_" + new Date().getTime())
.done(function (playlist) {
playlist.load("tracks").done(function () {
playlist.tracks.add.apply(playlist.tracks, arr).done(function () {
// Create list
var list = List.forCollection(playlist, {
style: 'rounded'
});
$('#playlistContainer').appendChild(list.node);
list.init();
});
});
});
}
// Get top track
function getTopTrack(artist, num) {
var promise = new models.Promise();
var artistTopList = Toplist.forArtist(artist);
artistTopList.tracks.snapshot(0, num).done(function (snapshot) {
snapshot.loadAll().done(function (tracks) {
promise.setDone(tracks[0]);
}).fail(function (f) {
promise.setFail(f);
});
});
return promise;
}
// Get Related
function getRelated(artist_uri) {
models.Artist
.fromURI(artist_uri)
.load('related')
.done(function (artist) {
artist.related.snapshot().done(function (snapshot) {
snapshot.loadAll().done(function (artists) {
var promises = [];
for (var i = 0; i < artists.length; i++) {
var promise = getTopTrack(artists[i], 1);
promises.push(promise);
}
models.Promise.join(promises)
.done(function (tracks) {
console.log('Loaded all tracks', tracks);
})
.fail(function (tracks) {
console.error('Failed to load at least one track.', tracks);
})
.always(function (tracks) {
// filter out results from failed promises
buildList(tracks.filter(function(t) {
return t !== undefined;
}));
});
});
});
});
}
getRelated('spotify:artist:2VAvhf61GgLYmC6C8anyX1');
});
The way I think about stuff like this is to imagine I'm on an super slow connection. If every callback (done, or the function passed to getTopTrack) took 2 seconds to respond, how do I need to structure my code to handle that?
How does that apply here? Well, when you call buildList, temp is actually empty. I suspect if you created the playlist first in getRelated, then added songs to it in your callback for getTopTrack, then it would work because the List would keep itself up to date.
Alternatively, you could rework getTopTrack to return a Promise, join all the top track promises together (see Promise doc's on each() and join()), then build the list when they're all complete.
As far as why you're getting multiple lists, it's because you append a new List each time you call buildList. Though I'm not seeing this behavior when I threw the code as is into my playground area. It only happens once, and when I reload application it starts from scratch. Perhaps you have a reload button which is calling getRelated.
Update I've been trying to get this to work, and having lots of trouble. Tried calling list.refresh after each add. Trying a Promise based method now, but still can't get the List to show anything.