Failing to run two pnp batch commands in spBeforeSave event

Hi,

I have two pnp batch commands that run in a spBeforeSave event on a (modal dialog) form. The first batch is to update existing items and the second is to save new items in the same related list.

The first update batch always appears to execute successfully, however new items are not created. In the console I can see a batch command is cancelled indicating the event has not waited for completion before closing the modal dialog:

I was hoping to be able to solve it referencing this thread Default Column Value not appearing in Form, and unable to run Async PnP in BeforeSave

However, I haven't been able to factor the code to work as expected within the spBeforeSave event. I have also transferred the code to run on a button click to test the batch updates work outside of the spBeforeSave event, which they do. It must be something about how I've got the code structured, any pointers?

This is my current code structure:

fd.spBeforeSave(function(spForm) {

	var list = sp.web.lists.getByTitle("Cumulative Forecast Hours");
	return list.items.get().then(function(items){
		
		// Use weekDataForUpdate array to create update items batch
		let batch = pnp.sp.createBatch();
		    
	    	$.each(weekDataForUpdate, function(i, item) {
			if(item.ProjectNumbers == projectNumber) {
				// Variables used for values below calculated here
				
				list.items.getById(item.Id).inBatch(batch).update({
					Hours_x0020_per_x0020_Week: totalHoursForWeek,
					Work_x0020_Package_x0020_Number: workPackageNumbers
				});
			}
		});
		
		batch.execute().then(function() {
	
			// Use WCDates array to create new items batch
			let newBatch = pnp.sp.createBatch();
			
			$.each(WCDatesArray, function(i, item) {
				if(item) {
					// Variables used for values below calculated here

					list.items.inBatch(newBatch).add({
						Week: WCDateString,
						Title: fd.field('Staff_x0020_ID').value,
						Hours_x0020_per_x0020_Week: fd.field('Hours_x0020_per_x0020_Week').value,
						ProjectNumbers: projectNumber,
						Work_x0020_Package_x0020_Number: workPackageNumber
					});
				}
			});
			
			newBatch.execute()
			
			return fd._vue.$nextTick();
		});
		
	});

});

Hello @Andrew,

Have you tested your code outside of spBeforeSave event? Are you getting any errors?

If no, you can try to run the code under spSaved, please find the code example in this post:

Hi @mnikitina,

Yes, I've tried running the code within an onclick function from a button and it successfully completed the pnp batch commands.

Thanks for the suggestion, that's something I've previously implemented successfully on a standard page form, although this time the form is launched in a modal window from a List/Library control - I didn't think the redirect was applicable for a modal or am I wrong?

Thanks,
Andrew

Hello @Andrew,

Yes, you are right.

In this case, you can run your code on change event of List or Library control. For instance, like this:

fd.control('SPDataTable1').$on('change', function(changeData) {
    if (changeData.type === 'add') {
        sp.web.lists.getByTitle("List").items.getById(changeData.itemId).update({
                Title: 'new title'
            }).then(function () {

        fd.control('SPDataTable1').refresh();

      });
    }
    
});

Hi @mnikitina,

An extra issue with the change event on the List/Library control is that I am on the 2019 on-premise forms software, so it's not available to me. I'm already checking the control for deletions in an interval function (comparing the 'current' to the original object array every second for any removed rows), so I could update this for the additions.

However, this wouldn't capture any row edits (i.e. not an addition or deletion) because I'm relying on the array length changing. Maybe I can successfully keep the update pnp batch command to deal with the edits in the spBeforeSave event. I'll update my code to try this approach then update the thread.

Hello @Andrew,

Ok, I see. Yes, for now, the change event is not available for the On-Premises version, but we're planing publishing the updates for On-Premises version in 3 months.

If you need updates earlier, we might be able to offer options here, but that would be paid support. If you are interested, you can write to support@plumsail.com to know the details.

Hi @mnikitina,

That's great to know that updates are coming to on-premises, it'll certainly save time to be able to use the onchange event for the List or Library control. Is there any notification that I can sign up for the release announcements?

In respect to my issue I have successfully migrated the new items pnp batch to run on the List/Library form page as part of the interval function, instead of the modal form spBeforeSave event.

However, I'm now seeing the update pnp batch not executed successfully which is still in the spBeforeSave event, the shorter spBeforeSave event code is now:

fd.spBeforeSave(function(spForm) {

	var list = sp.web.lists.getByTitle("Cumulative Forecast Hours");
	return list.items.get().then(function(items){
	
		var batch = pnp.sp.createBatch();
		
		// Loop weekDataForUpdate array which contains all rows requiring update
		$.each(weekDataForUpdate, function(i, item) {

				// Calculate update hours
				var totalHoursForWeek = Number(fd.field('Hours_x0020_per_x0020_Week').value) + item.Hours_x0020_per_x0020_Week;
				var workPackageNumbers = item.Work_x0020_Package_x0020_Number;

				list.items.getById(item.Id).inBatch(batch).update({
					Hours_x0020_per_x0020_Week: totalHoursForWeek,
					Work_x0020_Package_x0020_Number: workPackageNumbers
				});

		});
		
		batch.execute().then(function() {
		
			console.log("Executed update batch");
			return fd._vue.$nextTick();
		});
	});

});

Hello @Andrew,

You can create a custom button that updates items and saves the form using this code.

 var list = sp.web.lists.getByTitle("Cumulative Forecast Hours");
list.items.get().then(function(items){
	
		var batch = pnp.sp.createBatch();
		
		// Loop weekDataForUpdate array which contains all rows requiring update
		$.each(weekDataForUpdate, function(i, item) {

				// Calculate update hours
				var totalHoursForWeek = Number(fd.field('Hours_x0020_per_x0020_Week').value) + item.Hours_x0020_per_x0020_Week;
				var workPackageNumbers = item.Work_x0020_Package_x0020_Number;

				list.items.getById(item.Id).inBatch(batch).update({
					Hours_x0020_per_x0020_Week: totalHoursForWeek,
					Work_x0020_Package_x0020_Number: workPackageNumbers
				});

		});
		
		batch.execute().then(function() {
		  return fd.save()})
		});
1 Like

Hi @mnikitina,

Thanks for the suggestion, it gave me the idea to override the default save button function with that code (using fd.toolbar.buttons[0].click), so I can maintain the consistency of the UI/UX across the forms too.

It's now working as expected :smiley:

1 Like