Hi Justin,
Well, I finally achieved what I needed to do, but it hasn't been without a real struggle. Because I needed to read in and update a record in two tables with the same record IDs selected on the table view (long story, so wont bore you with the details about that) I thought the easiest approach would be to define a function and call it twice. I only discovered today about the asynchronous vs synchronous mode of making Ajax calls. All the while I'd been working on this stuff I couldn't quite understand why an alert I'd put at the end of the program (to prove I'd made it that far) was popping up before the Ajax calls had completed. Anyway, once I discovered that you can add async: false, to the properties of an Ajax call, which prevents any more Javascript executing until the Ajax call completes, everything got easier.
Whilst I am sure there are more elegant and thorough ways to program what I've done, I am going to post a copy of my stuff here also, as it is based on your code but a variation of what your code does. I removed the built-in delay, as it will only ever make four API calls, so should never hit the maximum allowed limit (I assume). I am also aware that it is flawed, in so much that Knack User Names are not necessarily unique, but I was preapred to put up with that, I've commented the code quite heavily, which was primarily to help myself, but I guess other Knack API/Javascript novices, like me, might glean something useful from it. Thanks again for your example above, without which I would have wasted even more time trying to get this working.
Cheers Steve
// Script to put tickbox selector on rows of Works Table View, plus Select All tickbox and Button to perform update.
// The update will add the IDs of the selected Works to the logged in User's Worksheet record within the two Worksheet tables.
// The user is initially prompted as to whether to start a new Worksheet or append to the existing list.
var addCheckboxes = function(view) {
// add the checkbox to to the header to select/unselect all
$('#' + view.key + '.kn-table thead tr').prepend('<th><input type="checkbox"></th>');
$('#' + view.key + '.kn-table thead input').change(function() {
$('.' + view.key + '.kn-table tbody tr input').each(function() {
$(this).attr('checked', $('#' + view.key + '.kn-table thead input').attr('checked') != undefined);
});
});
// add a checkbox to each row in the table body
$('#' + view.key + '.kn-table tbody tr').each(function() {
$(this).prepend('<td><input type="checkbox"></td>');
});
};
/**** CHANGE VIEW_ID TO YOUR OWN VIEW ID ****/
$(document).on('knack-view-render.view_13', function(event, view) {
// Add an update button
$('<button id="update"">Update My Worksheet</button>').insertAfter('.view-header');
// Add checkboxes to our table
addCheckboxes(view);
// Click event for the update button
$('#update').click(function() {
// Declare variable and Ask user if they want to add to existing Worksheet or start a new one
var ClearFlag = 0;
if (confirm("Start new Worksheet? (OK)" + "\n" + "To append to existing list click (Cancel)" + "\n" + "\n" + "Click and wait for page refresh.")) {
ClearFlag = 0;
} else {
ClearFlag = 1;
}
Knack.showSpinner();
//First let's define the Keys needed to call the API functions
var AppID = 'Knack App ID goes between these quotes';
var APIKey = 'Knack API Key goes between these quotes';
// Declare empty variables, which will be set and used at time of calling the function below
var TableID = '';
var FilterFieldID = '';
var TargetFieldID = '';
// Set up parameters for the first call of the function, which will update the first table
var TableID1 = 'object_48'; // This is the User Worksheets table
var FilterFieldID1 = 'field_504'; // This is the Name field
var TargetFieldID1 = 'field_506'; // This is the Works field
// Set up parameters for the second call of the function, which will update the second table
var TableID2 = 'object_47'; // This is the general Worksheets table
var FilterFieldID2 = 'field_493'; // This is the Name field
var TargetFieldID2 = 'field_494'; // This is the Works field
// Now get the user name to to use as the filter to retrieve the record from the table
var UserName = Knack.getUserAttributes().name;
// Begin record retrieve and update process
// Set the parameters for table 1 update
TableID = TableID1; // This is the User Worksheets table
FilterFieldID = FilterFieldID1; // This is the Name field
TargetFieldID = TargetFieldID1; // This is the Works field
//Call function to rereieve and update record in Table 1
$(function() {
GetThenUpdate(AppID, APIKey, UserName, TableID, FilterFieldID, TargetFieldID, ClearFlag);
});
// Set parameters for table 2 update
TableID = TableID2; // This is the User Worksheets table
FilterFieldID = FilterFieldID2; // This is the Name field
TargetFieldID = TargetFieldID2; // This is the Works field
//Call function to rereieve and update record in Table 2
$(function() {
GetThenUpdate(AppID, APIKey, UserName, TableID, FilterFieldID, TargetFieldID, ClearFlag);
});
// Definition of the function GetThenUpdate starts here
function GetThenUpdate(AppID, APIKey, UserName, TableID, FilterFieldID, TargetFieldID, ClearFlag) {
/*
console.log ('AppID is: ' + AppID);
console.log ('APIKey is: ' + APIKey);
console.log ('UserName is: ' + UserName);
console.log ('TableID is: ' + TableID);
console.log ('FilterFieldID is: ' + FilterFieldID);
console.log ('TargetFieldID is: ' + TargetFieldID);
console.log ('ClearFlag is: ' + ClearFlag);
alert('Just wrote the parameters passed to the function to the log');
*/
//getting Worksheet record to extract the record ID, plus the IDs of the Works connected to the record
var BaseRequestURL = 'https://api.knack.com/v1/objects/' + TableID + '/records';
var RequestFilter = [{
'field': FilterFieldID,
'operator': 'is',
'value': UserName
}];
var get_url = BaseRequestURL + '?filters=' + encodeURIComponent(JSON.stringify(RequestFilter));
$.ajax({
url: get_url,
type: 'GET',
async: false,
headers: {
'X-Knack-Application-Id': AppID,
'X-Knack-REST-API-Key': APIKey,
'Content-Type': 'application/json'
},
success: function(data) {
/*
console.log('Got record!');
console.log("data is:);
console.log(data);
console.log('End marker for data');
alert('GET just succeeded');
*/
// Out of the retieved record we need the record ID, plus the list of current IDs within the multi-select connector field
var TargetRecID = data.records[0].id;
var RawFieldID = TargetFieldID + '_raw';
var IDsInJSON = data.records[0][RawFieldID];
//This defines list as result of getIfNotSet function
IDsInJSON = getIfNotSet(IDsInJSON);
// This function resolves the error produced if the record has no records to get
function getIfNotSet(IDsInJSON) {
if (typeof IDsInJSON === 'undefined') {
return [];
} else {
return IDsInJSON;
}
}
// Need an array into which we can add the IDs from the JSON Object
var RecIDList = [];
/*
This next code iterates through the JSON object, picks out just the
IDs and adds each of them to RecIDList. If user opted for a new list
at the start, RecIDList will subsequently be cleared. Earlier attempts
to combine this function within CheckClearFlag didn't work, however.
Consequently leaving it here and ignoring the potential waste of processing.
*/
IDsInJSON.forEach(function(item) {
RecIDList.push(item.id);
});
// This defines the list as the result of the ClearFlag test
RecIDList = CheckClearFlag(RecIDList, ClearFlag);
// This function checks the ClearFlag and either clears down the existing list or leaves it as is
function CheckClearFlag(RecIDList, ClearFlag) {
if (ClearFlag == 0) {
return [];
} else {
return RecIDList;
}
}
/*
console.log('Next are the values for ClearFlag and RecIDList, after CheckClearFlag function call');
console.log(ClearFlag);
console.log(RecIDList);
console.log('End marker for ClearFlag and RecIDList');
alert('Just finished the two checks on RecIDList');
*/
// Now the ticked items are added to the RecIDList (which may or may not be empty).
$('#' + view.key + ' tbody input[type=checkbox]:checked').each(function() {
RecIDList.push(
$(this)
.closest('tr')
.attr('id')
); // record id
});
/*
console.log('Just finished adding ticked items, RecIDList now looks like this:');
console.log(RecIDList);
console.log('End marker for RecIDList');
alert('Just finished adding the ticked items (.push)');
*/
//I think this lifts out just the IDs
var webmerge_ids = [];
webmerge_ids = RecIDList.slice();
/*
console.log('Next is the value of webmerge_ids:');
console.log(webmerge_ids);
console.log('End marker for webmerge_ids');
alert('Just finished .slice command');
*/
// This pushes the value of the TargetFieldID variable into the data object used by the Ajax PUT
data[TargetFieldID] = webmerge_ids;
var puturl = 'https://api.knackhq.com/v1/objects/' + TableID + '/records/' + TargetRecID;
/*
console.log('Just about to do the PUT. next is puturl, the data array and TargetFieldID:');
console.log(puturl);
console.log(data);
console.log(TargetFieldID);
console.log('End marker for put_url, data array and TargetFieldID');
alert('Just about to do PUT, check console log for values');
*/
$.ajax({
url: puturl,
type: 'PUT',
async: false,
headers: {
'X-Knack-Application-Id': AppID,
'X-Knack-REST-API-Key': APIKey,
'Content-Type': 'application/json'
},
data: JSON.stringify(data),
success: function(response) {
TargetRecID = '';
TargetFieldID = '';
IDsInJSON = [];
RecIDList = [];
},
error: function(jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'No connection. Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 403) {
msg = 'Token or permissions Error [403]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.' + jqXHR.responseText;
}
console.log('Logging msg, jqXHR.status, puturl, headers and data');
console.log(msg);
console.log(jqXHR.status);
console.log(puturl);
console.log(headers);
console.log(data);
console.log('End marker of log entries');
}
}); // This is the end of the Ajax PUT
},
}); // This is the end of the Ajax GET
//alert ('Made it to then end of the function definition');
} // This is the end of the definition of the GetThenUpdate function
location.reload();
}); // This is the end of the on click function
}); // This is the end of the view render