Javascript & Promises & Async

I have code that I use to read a config file, save some data, then save the config file and lastly reload the page.

 

The reload has never worked and at times the read config did not occur. After a lot of research I discovered that JavaScript is very asynchronous. Meaning I could never really be guaranteed what code would run when. Most of my issue were due to using Ajax to do all the work, and the GET/PUT/POST being asynchronous.

I rewrote the code many times and finally found a solution. By using the async and await commands I got everything working correctly.

 

Here is the final code.

 

$(document).on('knack-record-create.view_1096', function(event, view, record) {
// Declare variables used
var Prefix = record.field_225_raw;
var Start = record.field_226_raw;
var End = record.field_227_raw;
var Total = record.field_584_raw;

var KnackAppID = "xxx"
var KnackAPIKey = "yyy"


// ******************************************************
// Fucntion to Get the Config data
// ******************************************************
async function GetConfig() {
return new Promise((resolve,reject) => {
$.ajax({
url: "https://api.knack.com/v1/objects/object_80/records/5d4e1092e169b3001096a207/",
type: "GET",
headers: {
"X-Knack-Application-Id": KnackAppID,
"X-Knack-REST-API-Key": KnackAPIKey
},
success: function(data) {
LastBarcode = data.field_784_raw
CurrentPrefix = data.field_785_raw
console.log('Get Config ' + LastBarcode)
resolve(data);
},
error: function(error) {
alert("Get Conifg Error: " + JSON.stringify(data));
Knack.hideSpinner();
reject(error);
}
})
})
}


// ******************************************************
// Fucntion to Save Barcode Data
// ******************************************************
async function PutBarcode() {
return new Promise((resolve,reject) => {
$.ajax({
url: "https://api.knackhq.com/v1/objects/object_10/records/" + record.id,
type: "PUT",
headers: {
"X-Knack-Application-Id": KnackAppID,
"X-Knack-REST-API-Key": KnackAPIKey
},
data: {
field_225: CurrentPrefix,
field_226: LastBarcode + 1,
field_227: LastBarcode + Total
},
success: function(data) {
console.log('Put Barcode ' + LastBarcode)
resolve(data);
},
error: function(data) {
console.log("Save Barcode Error: " + JSON.stringify(data));
Knack.hideSpinner();
reject(error);
}
});
})
}


// ******************************************************
// Fucntion to Save Config Data
// ******************************************************
async function PutConfig() {
return new Promise((resolve,reject) => {
$.ajax({
url: "https://api.knackhq.com/v1/objects/object_35/records/5d4e1092e169b3001096a207/",
type: "PUT",
headers: {
"X-Knack-Application-Id": KnackAppID,
"X-Knack-REST-API-Key": KnackAPIKey
},
data: {
field_784: LastBarcode + Total,
field_785: CurrentPrefix,
},
success: function(data) {
console.log('Put Config ' + LastBarcode)
resolve(data);
},
error: function(error) {
alert("Save Config Error: " + JSON.stringify(data));
Knack.hideSpinner();
reject(error);
}
});
})
}

// ******************************************************
// Main Code to Get Config, Update Barcodes and Save Config
// ******************************************************

const Main = async() => {
await GetConfig()
await PutBarcode()
await PutConfig()
console.log('Reload')
location.reload()
}

Main()

});

 

The last part of wrapping the function within another function was key in getting everything to work.

I'm not sure I fully understand the "why" of how this works, however it does appear do do what I was looking for and is much easier to read than the previous code.

 

Martin

 

 

Add complete option to your Ajax like this:

 $.ajax({
            type: "POST",
            //async: false,
            headers: {'X-Knack-Application-Id':'*******','X-Knack-REST-API-KEY':'*****','content-type':'application/json'},
            data: payload,
            complete:function(data) { 
                  //Refresh Table Content
                  Knack.views["view_65"].model.fetch();
            }, 
            success: function(response) {
                //console.log("Done!");
            }
            });

I'm not a very expert coder either hence many things are a mistery to me, but yet I have solved the same problem using jQuery deferred objects and callbacks. This makes the code a little bit tinier. 

Let's say I have the function myFunc that executes a ajax call. I will return the result of the call itself as such:

function myFunc(){
return $.ajax({ .... });
}

This will return a deferred object which is basically a promise in jQuery custom implementation. I will then manage it with a callback. So in my main code I will have something like:

myFunc().done(function(response){
console.log(response); // this is the response from the ajax call
// do things such a refresh the page here
});

Actually I don't know which is the best way to handle this, but since jQuery is handling promises already why to make additional code?

Davide

I see this is an old topic, but I am having a problem of a similar nature. I don’t like the standard “confirm” function/box in javascript so I created my own - based on some others I found online. I have an async function that returns a promise - this function displays the custom confirm popup and awaits for a button to be clicked to resolve. I initially used another async function to await and get the result and then return it to my knack submit button handler. While the code executed as it should, the knack form submitted before the response was back. So I tried making the knack submit click function async and getting the result from there with an await. Still executes as it should - the code after the await doesn’t execute until the response is in. However, knack goes ahead and submits the form before the response is in and I have the opportunity to return a true or false. Any ideas why this would happen? Thanks.

Example of the code:
$(document).on(‘knack-view-render.view_2423’, function(event, view) {

// Upon Submit

$(“#view_2423 .kn-button[type=submit]”).on(“click”, async function() {

let result = await confirmation_box();
console.log(`Confirmation result ${result}`);
console.log("got result");
if (result == true) {
	console.log("TRUE");
	return(true);
} else {console.log("FALSE"); return(false);}

});

});

async function confirmation_box() {
return new Promise(function(resolve){
const template = document.createElement(‘template’);
template.innerHTML = customConfirmBox;

// Elements
let confirmDisplay = template.content.querySelector('.confirm');
let btnOk = template.content.querySelector('#confirmButtonOk');
let btnCancel = template.content.querySelector('#confirmButtonCancel');

document.body.appendChild(template.content);

  btnOk.onclick = function() {
  console.log("confirm btn");
      document.body.removeChild(confirmDisplay);
      resolve(1);
   };

  btnCancel.onclick = function() {
  console.log("cancel btn");
      document.body.removeChild(confirmDisplay);
      resolve(0);
   };
});

}

Hi @MikeAntill41553,

Your form may be submitting because your code doesn’t contain the preventDefault() method.

Inside your click handler, pass the event parameter and call event.preventDefault() to prevent the form from submitting.

$('#' + view.key + ' .kn-button[type=submit]').on('click', async function(event) {
    // prevent the form from submitting
    event.preventDefault()
    
    // do stuff...
})

Haven’t evaluated the rest of the code but that’s one thing that stood out. :v:

Thanks. That did stop it from submitting. I then had to add code to force the submit once I got the confirmation click.

$(“#view_2423 .kn-button[type=submit]”).on(“click”, async function(e) {
e.preventDefault();
let result = await getConfirmation();
console.log(Confirmation result ${result});
if (result == true) {
console.log(“TRUE”);
$(‘#view_2423 .kn-button’).submit();
} else {console.log(“FALSE”); return false;}
});