You're going to have a lot of timing issues with this and you probably don't want to do it in PreSaveAction
, actually.
What it seems like you are tying to do is set something up to work like this:
- User opens the form.
- Your code checks the auto number list to get what should be the next quote number (but does not update the auto number list yet).
- You populate the quote number field in the current form with the next number.
- The user fills out the form.
- The user clicks Save.
- Your code increments and saves the auto number list item in the other list.
- The form is saved.
But let's look at the timing problem with that approach:
- User Adam opens the form.
- Your code checks the auto number list and gets the next quote number, which happens to be 101.
- You populate Adam's form's quote number field with 101.
- Adam decides to go get a cup of coffee.
- On a different computer, user Barbara opens the form.
- Your code checks the auto number list and gets the next quote number, which is still 101.
- You populate Barbara's quote number field with 101.
- Barbara fills out the form and clicks Save.
- Your code increments the auto number list and sets the next number as 102.
- Barbara's form is saved with quote number 101.
- Adam gets back with his coffee and fills out the form, and clicks Save.
- Your code increments from Adam's 101 and sets the next number as 102.
- Adam's form is saved, also with quote number 101.
A safer, but not entirely risk-free way to do it would be to get then next quote number when the form loads by using ExecuteOrDelayUntilScriptLoaded
so you can use the client context as soon as it's ready, and at the same time increment and save the next number available, and never worry about incrementing it using PreSaveAction
when the user clicks Save.
- Adam opens the form.
- Your code gets the next quote number from the other list (101), and immediately increments it (to 102) and updates that auto number list item.
- You populate Adam's form with quote number 101.
- Adam gets a phone call and is distracted.
- Barbara opens the form.
- Your code gets the next quote number, which is now already set as 102, and increments it to 103.
- You populate Barbara's form with quote number 102.
- Barbara saves her form with quote number 102.
- Adam eventually saves his form with quote number 101.
There's two risks with that approach:
- It's possible to drop/lose quote numbers, they are not guaranteed to be continuous. For instance, if Adam gets quote number 101 by opening the form, increments the next to 102, then Barbara gets 102 and increments the next to 103, what happens if Adam cancels the form and doesn't save it? There's no item saved that has quote number 101, they would skip from 100 to 102. If that's not a big deal than this is a much better solution.
- There is a very, very small chance that you could still have a timing issue. If Adam and Barbara both open the form at nearly exactly the same time, it is possible that because of variances in network traffic etc., both of the requests for the next number go through and return the same number before either one of them is able to increment and update the next number. This would be incredibly unlikely, but it is possible.
All that being said,
if you do not want gaps in the quote numbers and only ever want to increment the next quote number when someone clicks Save and commits to submitting the form, you can retrieve the next number from the other list, populate that into the form, and then increment and save the next number in the other list, all from PreSaveAction
, but it gets very tricky because PreSaveAction
is designed to be a synchronous function, and all that retrieving and updating is done asynchronously.
Also, if you do it from PreSaveAction
, you obviously can't pre-populate the form with the quote number so the person won't see what quote number they are going to be assigned.
In order to control the execution flow and trigger some async functionality from PreSaveAction
and wait for the results to return before allowing the form to save, you have to set a flag variable to know when your async operations are done, and then re-trigger the Save button click from within your own code to re-start the form submission process.
I see you're using jQuery, so I will use that to kind of show you what you can do, but obviously this is kind of pseudo code just to show you an example and the selectors etc. are not accurate. Also I'm rusty on my JSOM so that might be a little off too, but you will get the idea.
// set up a flag variable to keep track of whether or not
// you finished all your async actions
var nextQuoteNumWasUpdated = false;
// set this up as a global variable so that you
// don't have to worry about passing it around
// between callback functions
var quoteNumListItem = null;
function PreSaveAction() {
if (!nextQuoteNumWasUpdated) {
// you haven't retrieved or incremented the next quote number yet
// disable the save button so people don't accidentally click twice
$('#SaveButton').prop('disabled', true);
// start that async process
retrieveNextQuoteNumber();
// you cannot wait for an async process to finish here,
// it will not block the code execution, so you have to
// allow PreSaveAction to finish, but you don't want
// the form saved yet, so tell it it can't save yet
// by returning false
return false;
} else {
// the flag was set to true, so you
// have successfully retrieved the next quote number,
// populated it in this form, and
// incremented and updated the next quote number,
// so allow the form to save by returning true
return true;
}
}
function retrieveNextQuoteNumber() {
var clientContext = new SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle('AutoQuoteNumberTest');
quoteNumListItem = list.getItemById(1);
clientContext.load(quoteNumListItem, 'NextQuoteNumber');
// send the async request to the server and specify your callback functions
clientContext.executeQueryAsync(retrieveNextNumSucceeded, retrieveNextNumFailed);
}
function retrieveNextNumSucceeded() {
// get the number from the item you retrieved
var nextQuoteNumber = quoteNumListItem.get_item('NextQuoteNumber');
// set the value in your form
$("input[title^='Quote Number']").val(nextQuoteNumber);
// increment the number and update the other list
var incrementedNumber = nextQuoteNumber + 1;
var clientContext = new SP.ClientContext.get_current();
var list = clientContext.get_web().get_lists().getByTitle('AutoQuoteNumberTest');
var listItem = list.getItemById(1);
listItem.set_item('NextQuoteNumber', incrementedNumber);
listItem.update();
// send the async request to the server and specify your callback functions
clientContext.executeQueryAsync(updateNextNumSucceeded, updateNextNumFailed);
}
function retrieveNextNumFailed() {
alert('Failed to retrieve the next quote number: ' + args.get_message());
}
function updateNextNumSucceeded() {
// update was successful, so you are all
// done with your async operations, so now you
// can allow the form to save.
// first, set your flag so that PreSaveAction knows you are done
nextQuoteNumWasUpdated = true;
// now, re-trigger the Save button to finally save the form
$('#SaveButton').prop('disabled', false);
$('#SavebUtton').click();
}
function updateNextNumFailed(sender, args) {
alert('Could not able to update item: ' + args.get_message());
}