Trigger Form Submit for a specific record from Javascript?

Is there any syntax which would, from Javascript, trigger submission of a particular form if I have the URL with a record id?

In other words, I want to run the submit button on this page URL
https://lombardo.knack.com/myapp#pagename/detailpagename/63ba25a899982f001e44eec6/
(I have a number of workflow rules on the form submit)

I can do ONE by setting that form and then autosubmit, then set the URL as my window location in JS.

However, I have a list of these (say 4) that I need to do in a batch. No matter how I try it, I can’t open the same form (different record URL) multiple times in a row successfully. If I put in enough pauses it might get two of them done, but it takes forever to run. My workaround is to take the user to the pre-filtered parent form where they can click to open each autosubmit form themself and it actually works pretty fast. But I was really hoping to automate the entire thing.

@RobinB

Since you’re doing a batch, usually the requirement is for the batch to succeed or fail together so I’m assuming that’s the goal here. If that’s the case you might want to look into the syntax for Promise.all(). It accepts an array of promises like this:

const allPromises = Promise.all([promise1, promise2, promise3])

allPromises.then(results => {
  results
}).catch(error => {
  error
})

Ian

That’s not what I’m looking for, but I will file that away for future reference, thank you. Nested promises get confusing!

Basically, previous programming has created a filtered list of records (invitations to bid for certain vendors) which contain an email address and I want to get to the detail record for each and use the workflow email function in the form submit rules. I can make the user click for each detail page manually and auto-submit the form, but I would rather do all of them automatically with the code that created these records in the first place. (User has created a Job, then selected a number of vendors and then we’re sending them all an invitation to bid on the job with a personalized URL where each can respond and submit their bid.)

Using promises won’t help because my real problem is a timing issue of physically opening a window for each record so that the form can autosubmit itself. It be much more efficient (and maybe actually work LOL) to just trigger the form submission without actually having the browser open the form.

I know I could probably write something custom for sending the emails, but the built-in workflow email feature is so easy to use and update that I’d prefer to stick with it.

@RobinB

Thanks for sharing your details here:

my real problem is a timing issue of physically opening a window for each record so that the form can autosubmit itself.

Here ya go!

$(document).on('knack-view-render.view_25', function(event, view, data) {  
  // Step 1: Get each Knack record
  // TODO

  // Step 2: Pass the record ID and the Form URL to this custom function. 
  openWindowAndSubmitForm('https://example.knack.com/ordering-app#orders/vieworderdetails2/6195543121b4df072666eeee/edit-order', '6195543121b4df072666eeee')
})

// On render of the Form...
$(document).on('knack-view-render.view_100', function(event, view, data) {
  if (getQueryVariable('autosubmit')) {
    removeQueryString()
    $(`#${view.key} form`).submit()
  }
})

function openWindowAndSubmitForm(formURL, recordID) {
 // physically open a window and autosubmit a form 
  const url =`${formURL}/${recordID}?autosubmit`
  window.open(url)
}

function getQueryVariable(variable) {
    var hash = window.location.hash;
    var rightOfSlash = hash.replace(/\/$/, "").split('/').pop(); // First removes a trailing slash if one exists. Then, splits the string into an array on / and pops off the last element, returning everything to the right of the final slash.
    var firstCharacter = rightOfSlash.charAt(0);
    if (firstCharacter != '?') {
      // console.log('no query string was found in URL');
      return false;
    }
    var query = rightOfSlash.substring(1);
    var vars = query.split('&'); // creates an array of elements using '&' as delimiter
    for (var i = 0; i < vars.length; i++) { // iterates through these array items...
        var pair = vars[i].split('='); // splits each item on in that array on "=" creating a pair which is an array itself, like this: [param, value]. In other words pair[0] is the param and pair[1] is the value.
        if (pair[0] == variable) { // if a pair's parameter matches the variable we are seeking, it returns that pair's value. 
            return pair[1];
        }
    }
}

function removeQueryString() {
  let path = window.location.pathname;
  let hash = Knack.scene_hash;
  window.history.replaceState({}, document.title, path + hash);
}

The first part would happen on click of a button not view render, but I’m sure you get the idea.
:metal:

The problem is that this does not work to open multiple windows (in Chrome). It’s a browser issue that I’ve been unable to get around, so I was hoping there was some kind of Knack function/syntax that would let me call the submit button’s function without using window.open.

To demonstrate, I simplified this function to just open three separate windows in a row and it will not work consistently even with timeout or putting a pause in between. From what I’ve read, if I get the timing within specific parameters the browser MIGHT open multiple popups, but it has been unreliable for me. Usually it opens the first one and then stops.


async function OpenAutosubmitForm(PageUrl, WindowName) {        // PageUrl contains record id
    window.open('https://www.google.com', WindowName+"1");     
    window.open('https://www.integritivity.com', WindowName+"2");
    window.open('https://www.atlasquest.com', WindowName+"3");         // with no pauses, this is the one that gets opened
    window.open(PageUrl, WindowName);
        /*
        setTimeout(() => window.open('https://www.google.com', WindowName+"1"), 0);
        setTimeout(() => window.open('https://www.integritivity.com', WindowName+"2"), 0);
        setTimeout(() => window.open('https://www.atlasquest.com', WindowName+"3"), 0);
        /*
        await window.open('https://www.google.com', WindowName+"1");     
        await window.open('https://www.integritivity.com', WindowName+"2");
        await window.open('https://www.atlasquest.com', WindowName+"3");         // with no pauses, this is the one that gets opened
        await window.open(PageUrl, WindowName);
        //await window.open(PageUrl, '_blank');
        */
}

@RobinB
That’s weird because I’m using Chrome
Version 96.0.4664.110 (Official Build) (x86_64)

$(document).on('knack-view-render.view_25', function(event, view, data) {
  openThreeWindows()
});

function openThreeWindows() {
  window.open('https://google.com')
  window.open('https://google.com')
  window.open('https://google.com')
}

Must be a version issue or something. Too bad.

@RobinB

Putting aside the window.open mystery for a moment…

I honestly think the best syntax here is await (i.e. Promises).

Please watch this video. Here’s what happens:

  1. The user wants to autosubmit a form 4 times.
  2. On click of Autosubmit form, 4 API calls are made to the form, awaiting each one.

This workflow is what you’re trying to do, I believe, unless I’m missing something. :thinking:

Here’s the code from the demo:

async function knackAPI(method, sceneKey, viewKey, recordId, fields) {
  const url = `https://api.knack.com/v1/pages/${sceneKey}/views/${viewKey}/records/${recordId}`;
  const options = {
    method,
    body: JSON.stringify(fields),
    headers: {
      'X-Knack-Application-Id': Knack.application_id, 
      'X-Knack-REST-API-Key': 'knack', 
      'content-type': 'application/json',
      }
  }

  try {
    const res = await fetch(url, options)
    const data = await res.json()
    console.log(data)
  } catch (error) {
    // handle errors
  }
} 

$(document).on('knack-view-render.view_40', async function(event, view, data) {
    await knackAPI('POST', 'scene_43', 'view_99', '', {})
    await knackAPI('POST', 'scene_43', 'view_99', '', {})
    await knackAPI('POST', 'scene_43', 'view_99', '', {})
    await knackAPI('POST', 'scene_43', 'view_99', '', {})
})



If you want to get the detail record before submitting the form, then you can alternate like this:

await knackAPI('GET', ...)
await knackAPI('POST', ...)

await knackAPI('GET', ...)
await knackAPI('POST', ...)

await knackAPI('GET', ...)
await knackAPI('POST', ...)

// etc

If you want to show the progress text as seen in the video ("Submitted one time... Submitted two times... etc") you can add it underneath each `await` call.

Thank you, this helped me to find my browser issue! (I am actually using await but did not post it.)
I am using the same version of Chrome, but pressed harder knowing that you are able to make it work.

I got it to work simply by enabling popups for knack.com

  1. At the top right of a Chrome window, click More. Settings.
  2. Privacy and Security. Site Settings.
  3. Pop-ups and redirects.
  4. Add a site to enable for popups: [*.]knack.com

Thank you for taking time to consider my issue!!

1 Like

Awesome! Glad everything worked out.