Power Pages archive

Asynchronously Saving a PowerApps Portal Entity Form

Saving an entity form in the background with jQuery, without reloading the page.

Updated 3 min readSuperseded

Where this stands in 2026

Superseded

Use the official options now. The Power Pages Web API is generally available and handles create, read, update and delete from JavaScript. Server logic (generally available since April 2026) runs your own code on the server, and the Client API’s $pages.ajax (in preview) wraps those calls for you. The postback trick in this post was never supported and may break.

Official docs for today’s approach

Written in 2021 for PowerApps Portals. See what things are called now.

Microsoft has since renamed the product and most of its parts. The text keeps the original terms.

In this noteToday
PowerApps PortalsPower Pages
EntityTable
Entity FormBasic form

Overview

Have you ever wanted to submit an Entity Form without forcing your users to wait for the screen to completely refresh?

Have you ever wanted to add in a timer-based auto-save functionality?

Have you ever dug through the client-side code and noticed that there’s a hidden option, just out of reach, indicating an async save process exists?

Well, I have, and after a few attempts over the years, I’ve found it really doesn’t take much code to actually implement.

Minimum Requirements

At its simplest, all you really need is the following code snippet. This identifies the form expecting a POST method (as opposed to the GET of the Search functionality), identifies the target URL, adds the necessary __EVENTTARGET data and submits the form.

JavaScript
var $form = $("form[method='post']");
$form[0].__EVENTTARGET.value = $(".submit-btn").attr('name');
$.post(
    $form[0].action,
    $form.serialize()
).done(function(data) {
    console.log("success!");
}).fail(function (data) {
    console.log("fail :(");
});

Gap Considerations

  • No pre-submit validation
  • No post-submit validation
  • No status updates about where the process is at
  • It won’t really work on Insert Entity Forms

Most of these we could fix quickly, while others range from complex to very complex to correct.

If you need to work around a large number of Required Fields, you could look to implement some of the suggestions from my “Save vs. Submit” post.

With that in mind, you could consider setting up the following:

  1. Auto-save functionality (timer or after each field is changed) that only checks server-side validations (“Business Required” fields, Entity Form Metadata “Required”, etc.)
  2. Standard Submit button that fills a hidden field to indicate “completion” of the record
  3. Overriding entityFormClientValidate to check a specific Validation Group, which is created on load (consider the simplified & extensive logic found on the Code Snippets page)

With this, the form would save as users complete fields so that their data isn’t lost. Once they’ve submitted it, you could verify the submission and look to lock the form – now you’d only need one button.

Improving the Code

To improve this code, we should look to do a few things:

  1. Check Client-Side Validation Pre-Submit
  2. Check Validations Post-Submit
    • I’ve checked against the first level of validations below, but the code could be updated to include the custom plugin messages that typically appear at the top of the page as well
  3. Have an area dedicated to asynchronous responses (when needed)
  4. Add some defensive coding to protect against issues (such as the form not being present)
JavaScript
// Enhanced
$(document).ready(function () {
    var $updateBtn = $("#UpdateButton");
    var $saveBtn = $updateBtn
        .clone()
        .attr("id", "SaveButton")
        .removeAttr("onclick")
        .removeClass("btn-primary")
        .addClass("btn-default")
        .val("Save Async")
        .insertBefore($updateBtn);
    $updateBtn.attr(
        "onclick", 
        "$('#new_submitdatefield').next('div.datetimepicker').datetimepicker().data('DateTimePicker').date(new moment());" + 
        $updateBtn.attr("onclick"));

    var $asyncStatus = $("<div></div>")
    .addClass("alert alert-block alert-error alert-danger")
    .attr("id", "AsyncStatus")
    .attr("role", "alert")
    .hide()
    .insertAfter($("div.actions"));

    $saveBtn.click(function () {
        $asyncStatus
        .text("")
        .hide();
        if (Page_IsValid === false) {
            $asyncStatus
            .text("The form has failed initial validation.")
            .show();
            return;
        }
        var saveBtn = this;
        saveBtn.value = "Saving..";
        saveBtn.disabled = true;

        var $form = $("form[method='post']");
        if ($form.length === 0) {
            this.value = "Error";
            return;
        }
        $('#new_submitdatefield')
            .next('div.datetimepicker')
            .datetimepicker()
            .data('DateTimePicker')
            .date(null);
        $form[0].__EVENTTARGET.value = $(".submit-btn").attr('name');
        $.post(
            $form[0].action,
            $form.serialize()
        ).done(function(data) {
            var $submittedValidations = $(data).find(".validation-summary");
            if ($submittedValidations.children().length > 0 || 
              $submittedValidations.text().trim().length > 0) {
                $asyncStatus
                .text("Please see below as to why the form couldn't be saved.")
                .append("<hr/>")
                .append($submittedValidations)
                .show();
            }
        }).fail(function (data) {
            $asyncStatus
            .text("Something went wrong and we are unable to save the form.")
            .show();
        }).always(function () {
            saveBtn.value = "Save Async";
            saveBtn.disabled = false;
        });
    });
});

Async in Action

Below you will find examples where I’ve updated my Save as Draft work to replace the Save button with a “Save Async” button. They showcase the happy path, a failed client validation, and a failed server validation.

Figure 1Async Save success: refresh shows persistence

Recreated illustration: Async Save Success: clicking Save Async posts the form in the background without a page reload, and refreshing the page shows the change was saved.

  1. Callout 1: While the background POST runs, the button reads “Saving..” and is disabled.
  2. Callout 2: After a manual refresh, the new value is there: it was saved without a full postback.

Recreated illustration. The original screenshot was lost with the old site; this drawing follows the article text.

Refresh shows persistence

Figure 2Async Save, server error: transfers the validation summary

Recreated illustration: Async Save - Server Error: the server rejects the save, and the validation summary from the response is copied into the #AsyncStatus alert.

  1. Callout 1: The #AsyncStatus alert, inserted after the form actions.
  2. Callout 2: The .validation-summary lifted from the server’s HTML response.

Recreated illustration. The original screenshot was lost with the old site; this drawing follows the article text.

Transfers Validation Summary

Figure 3Async Save, client error: standard message

Recreated illustration: Async Save - Client Error: client-side validation fails before anything is posted, and a standard message is shown; Page_Validate() could be used to show the normal error list instead.

  1. Callout 1: Page_IsValid is false, so nothing is posted.
  2. Callout 2: A generic message. Calling Page_Validate() would show the portal’s normal validation list instead.

Recreated illustration. The original screenshot was lost with the old site; this drawing follows the article text.

Standard Message – Use Page_Validate() for normal error

Closing Thoughts

Alternatively, you could look to implement the same using the Portal’s native Web API support. As of this writing, it’s still very cumbersome to set up and, in my opinion, would require far more development effort. I’ve also seen developers come up with really interesting ways to AJAX GET an Entity Form via the standard FetchXML-as-an-API trick, in order to post it asynchronously. Unfortunately, this typically requires writing code to fill specific fields or do the mapping.

My hope is that this code sheds some light on additional possibilities. Feel free to let me know if it works for you, or if you’ve found something better.

Restored in 2026 from the Internet Archive at its original address. Figures are recreated illustrations of lost screenshots; the text was lightly copy-edited.