How to Save Record ID as a Field Value (View-Based)

How to Save Record ID as a Field Value

I recently stumbled upon how amazing it would be if I could store the Record ID as a field value. So, I did. And learned you can do some amazing stuff with the Record ID such as creating custom URL paths in email, creating custom URL paths via Javascript, and making view-based API ajax calls from any view for any object (as long as you hide the record id somewhere accessible). If any of that interests you then here is how to save the Record ID into a field value upon record creation using a view-based API request. You can save the Record ID whether the user is logged-in or not.

Javascript:

// Function to Save Record ID
function save_Record_ID(recordID, scene_and_view, field_number) {
$.ajax({
url: "https://api.knack.com/v1/pages/" + scene_and_view + "/records/" + recordID,
type: "PUT",
headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-Key": `knack`,
"Authorization": Knack.getUserToken()
},
data: field_number,
tryCount: 0,
retryLimit: 3,
success: function(response) {
console.log("Captured Record ID"); // Success Message in Console Log
Knack.hideSpinner();
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
this.tryCount++;
let tryCount = this.tryCount, retryLimit = this.retryLimit, seconds;
if (tryCount <= retryLimit) { //try again
switch(tryCount) {
case 1:
case 2: seconds = 5; break;
case 3: seconds = 10; break; }
let timeout = seconds * 1000;
console.log("Error: " + XMLHttpRequest.status + " " + XMLHttpRequest.statusText + "\nRetry Count: " + tryCount + "\nRetrying in " + seconds + " seconds")
let ajaxObject = this;
window.setTimeout(function(){
$.ajax(ajaxObject);
}, timeout);
} else {
console.log("Failed to Capture Record ID");
}
}
});
}

// Listens for record creation and saves the record id when record is created.
$(document).on('knack-record-create.view_638', function(event, view, record) { // UPDATE the view number to the form used to create a record
const field_number = {field_667 : recordId}; // UPDATE the field number to the field used for storing the record id
const scene_number = "scene_238"; // UPDATE to the scene number for the form used to save the record id
const view_number = "view_2732"; // UPDATE to the view number for the form used to save the record id
save_Record_Id(record.id, scene_number & "/views/" & view_number, field_number);
});

// This is the separate edit form used to save the record id
// This removes the view from HTML upon rendering to prevent data manipulation.
$(document).on('knack-view-render.view_2732', function (event, view, record) {
$('#' + view.key).remove();
});

CSS:

/* Hide Second Form Just Incase. Don't substitute this with display:none */
#view_2732 {
position: absolute;
top: -9999px;
left: -9999px;
}

Code Tips & Tricks:

Keep in mind that the ajax url points to a seperate form (highly recommended to prevent record rule mayhem). Your users who submitted the first form will need to have access-rights to the second form in order for this to work. Personally, I always put my second form on the very next page after the first one (or within the same tree) to ensure my users will have access to it. On the second form, feel free to set up Record Rules that share the Record ID with any other records that need it. The CSS is optional but recommended to hide the second form before if is removed by javascript as a "just in case" precaution.

Speaking of precautions, you can also have a Knack Page Rule setup to redirect the user to the parent page (or any other page ie custom error page) if the page with the second form is ever accessed by a user (by some magic). This ensures that users cannot access this page and submit the form manually. To do that, you'll need to dedicate an entire page to the second form and ensure it is in the same tree as the record being created. Then, if you want, you can put any other hidden forms there too.

2 Likes

Hey 397391547191,

That is what I was referring to! Something cool about the Console Log is if something breaks then you can actually click the underlined text on the right-hand side (the text that start with "k 070761a...") and, most of the time, it will take you to the specific line in the custom code that is causing the problem. That being said, the console is saying there is a syntax error somewhere in the code. Annnnd I feel like I know what it is already! I should have caught this yesterday but it's been awhile since I have messed with this specific code.

I see you modified the headers section in the AJAX code. It actually doesn't need to be modified at all. If you replace your header section using this one (without any edits) then it should work just fine:

headers: {
"X-Knack-Application-Id": Knack.application_id,
"X-Knack-REST-API-Key": `knack`,
"Authorization": Knack.getUserToken()
},

I know that's a little weird. Naturally, one would think you'd need to input your Application ID and Rest API Key but you actually don't have to do that in a view-based ajax request (which is fantastic because exposing the API information from your front-end code is a huge security risk).

Note: That should solve your problem. Once that's fixed, your Console Log should start showing the Console Log messages from my code like "Captured Request ID" if it works or "Error: Retry Count: 1..." if it fails. This code will attempt saving the record id up to three times maximum when it fails (because sometimes the Knack server is busy and code doesn't understand the concept of being patient).

If this doesn't work then feel free to email me at robert.hill@tuta.io and we can setup a zoom or something to figure it out. I am on EST in the US. We can talk and find a good time if needed :)

1 Like

Hey 397391547191,

This is probably one of the hardest things to do for a JavaScript newbie so kudos for tackling this one (AJAX requests... what a nightmare lol)! Anyways, I do see an issue in your code that is probably causing your problem. Here's what I would suggest:

  • The "URL" section in your AJAX request should be referencing view_372 instead of view_370 (which means you'll have to update the scene number there as well).
  • Also I am assuming your view_372 has a text field (field_182) for storing the record id? Just want to make sure :)

The reason we are using view_372 in our AJAX URL is because view_372 contains the text field (field_182) for storing the record id and this "PUT" type request will access that form behind the scenes and use it to store the record id created from view_370's "submit" event. Let me know if that helps or if it doesn't and we can troubleshoot further. If it doesn't work, it would be helpful if you could pull up the Developer window in your web browser and tell me what the Console Log says after you create a record using the form on view_370.

Hey Kimberly,

This bit of code is pretty complex, it took me quite a bit of time to wrap my head around this concept also. However I'm glad to help! I have two forms here. Let me know if you run into any issues. It's good practice for me to explain how this stuff works just as it's good practice to learn it. I agree, it should be easier and more native in Knack to capture a Record ID however learning this stuff will open many doors for your apps that were once closed.

First Form

The first form is view_638 which is the form that actually creates the record. This is the form that we want to capture the Record ID from. So, this part is easy. You just need to update this View ID to match yours for the form that you want to capture the Record ID from.

Second Form 

The second form is view_2732 and this is where it gets complicated. This second form is what does all of the work in our AJAX request. This second form should update the created record (you can ensure that by having your first form lead to a child page that contains this form). And, on this form, you will NEED to have a text field for inputting the Record ID. The second form should look something like this:

![](upload://liACgrbCc9kIrG34vkKfr2acsWA.png)

This second form should never be seen by a user at anytime. We are using this form strictly to automatically input the Record ID using Javascript and that's it. Because we don't want people updating the Record ID manually, that's madness haha. This is why I remove the second form as soon as it loads in Javascript and use CSS to hide it (just in case the Javascript takes it's sweet time). That being said, one more comment about this second form. Our users NEED to have access to it. This form cannot be hidden behind a login page our users don't have access to. The reason for this is because we are going to automatically complete this form on their behalf using Javascript and, in order to do that, they need access rights to the form. We're just never letting them fill it out manually. 

AJAX PUT Request

Now let's talk about the AJAX function. You will need to update the URL with the Scene ID and View ID for the second form (which is view_2732 in my example). You will also need to update "field_667" with your Field ID. This Field ID will be the one that refers to the field that you put on your second form. In other words, the field that actually captures the Record ID.

Something to note about the AJAX PUT Request, this version is a View-based request. That means if you have any record rules or email rules on your second form then they will be run too. This is because the system is treating our PUT request as if we manually completed the form.

Sorry, also, in the section for the 2nd form, is view 2732 supposed to be the same as the view at the very beginning of the code? I would have thought those would be different. Thank you so much!

397252071171 I'm going to give this a shot... Can you please clarify where view 638 came from in your code? Thanks so much!

I appreciate what you've shared here, but I'm afraid it's over my head. I can't believe there's not a simpler way to do this. It's crazy to me that you can't easily pull a Record ID (or URL, as that's what I'm really after) for any object. I mean, if I send someone a URL to a specific record and that person doesn't have access, it will redirect them or hide the content. I don't get why Knack hasn't made this simpler. 

RobertHill84742, thanks so much for this.
I have commented out the function call to actually record the id for troubleshooting.
When I create the new record and alert the record id, I get the id, but when I console log on the next line, I keep getting “0”

I did change the value in the Key:Value pair of the const field_number to record.id, but only because I would get an error in the console.log saying that RecordID was undefined.

Any ideas? The form I use to create the object has a submit rule that redirects to a new child page. I think the variable is destroyed when the new scene renders. Maybe I’m not sure how you’re getting to the next next page that shows the new record. :thinking: Hmmm, just writing that gives me an idea. Off to code, test and troubleshoot!

// Listens for record creation and saves the record id when record is created.
$(document).on(‘knack-record-create.view_223’, function(event, view, record) { // UPDATE the view number to the form used to create a record
const field_number = {field_255 : record.id}; // UPDATE the field number to the field used for storing the record id
const scene_number = “scene_119”; // UPDATE to the scene number for the form used to save the record id
const view_number = “view_239”; // UPDATE to the view number for the form used to save the record id
//save_Record_ID(record.id, scene_number & “/views/” & view_number, field_number);
alert(record.id);
console.log (‘Record ID:’+ record.id + ‘\n Scene and View Path :’ + scene_number & “/views/” & view_number +’\n Field: ’ + field_number );

});

Interesting. When I changed:

save_Record_ID(record.id, scene_number & “/views/” & view_number, field_number);

to

save_Record_ID(record.id, scene_number + “/views/” + view_number, field_number);

Things seem to work fine.

YAY!

2 Likes

Oh wow! Sorry, that’s my bad. When I posted this, I must have been typing up some Sheets formulas on the other screen and used the “&” symbol instead of “+” to concatenate strings. It looks like I also had a leftover variable name in my original post that wasn’t referenced anywhere causing issue. I bet things got lost in translation between copying/pasting the code from my app to here because I had to manually type some of it out to remove extra stuff that wasn’t exactly relevant.

I am making a new reply in the comment’s section here that fixes both of those errors. I am posting the updated code in the comments section because Knack Forums won’t let me edit my original post (probably because we migrated to this new forum, I don’t know).

1 Like

No worries. I’m just happy that people share so freely.
Thanks again.!

:triangular_flag_on_post: Original Post Revisions and Bug Fixes

How to Save Record ID as a Field Value

I recently stumbled upon how amazing it would be if I could store the Record ID as a field value. So, I did. And learned you can do some amazing stuff with the Record ID such as creating custom URL paths in email, creating custom URL paths via Javascript, and making view-based API ajax calls from any view for any object (as long as you hide the record id somewhere accessible). If any of that interests you then here is how to save the Record ID into a field value upon record creation using a view-based API request. You can save the Record ID whether the user is logged-in or not.

Javascript:

// Function to Save Record ID
function save_Record_ID(recordID, scene_and_view, field_number) {
  $.ajax({
    url: "https://api.knack.com/v1/pages/" + scene_and_view + "/records/" + recordID,
    type: "PUT", 
    headers: {
      "X-Knack-Application-Id": Knack.application_id,
      "X-Knack-REST-API-Key": `knack`,
      "Authorization": Knack.getUserToken()
    },
    data: field_number,
    tryCount: 0,
    retryLimit: 3,
    success: function(response) {
      console.log("Captured Record ID"); // Success Message in Console Log
      Knack.hideSpinner();
    },
    error : function(XMLHttpRequest, textStatus, errorThrown) {
      this.tryCount++;
      let tryCount = this.tryCount, retryLimit = this.retryLimit, seconds; 
      if (tryCount <= retryLimit) { //try again
        switch(tryCount) {
          case 1:
          case 2: seconds = 5; break;
          case 3: seconds = 10; break; }
        let timeout = seconds * 1000;
        console.log("Error: " + XMLHttpRequest.status + " " + XMLHttpRequest.statusText + "\nRetry Count: " + tryCount + "\nRetrying in " + seconds + " seconds")
        let ajaxObject = this;
        window.setTimeout(function(){
          $.ajax(ajaxObject);
        }, timeout);
      } else {
        console.log("Failed to Capture Record ID");
      }
    }
  });
}

// Listens for record creation and saves the record id when record is created.
$(document).on('knack-record-create.view_638', function(event, view, record) { // UPDATE the view number to the form used to create a record
  const field_number = {field_667 : record.id}; // UPDATE the field number to the field used for storing the record id
  const scene_number = "scene_238"; // UPDATE to the scene number for the form used to save the record id
  const view_number = "view_2732"; // UPDATE to the view number for the form used to save the record id
  save_Record_Id(record.id, scene_number + "/views/" + view_number, field_number);
});

// This is the separate edit form used to save the record id
// This removes the view from HTML upon rendering to prevent data manipulation.
$(document).on('knack-view-render.view_2732', function (event, view, record) {
  $('#' + view.key).remove(); 
});

CSS:

/* Hide Second Form Just Incase. Don't substitute this with display:none */
#view_2732 {
   position: absolute; 
   top: -9999px; 
   left: -9999px;
}

Code Tips & Tricks:

Keep in mind that the ajax url points to a seperate form (highly recommended to prevent record rule mayhem). Your users who submitted the first form will need to have access-rights to the second form in order for this to work. Personally, I always put my second form on the very next page after the first one (or within the same tree) to ensure my users will have access to it. On the second form, feel free to set up Record Rules that share the Record ID with any other records that need it. The CSS is optional but recommended to hide the second form before if is removed by javascript as a "just in case" precaution.

Speaking of precautions, you can also have a Knack Page Rule setup to redirect the user to the parent page (or any other page ie custom error page) if the page with the second form is ever accessed by a user (by some magic). This ensures that users cannot access this page and submit the form manually. To do that, you’ll need to dedicate an entire page to the second form and ensure it is in the same tree as the record being created. Then, if you want, you can put any other hidden forms there too.

1 Like

As we are supposed to be No Coders here, I thought I would propose and alternative (and very simple) alternative - Integromat.

All you need to do is to trigger a Scenario based on a new record being created and then have an Update Record module to add the Record ID into your text field:

To be transparent, you can probably do this with Zapier as well - but I would strongly recommend learning Integromat to all Knacksters.

4 Likes

Hi Robert - When using this the first form keeps on thinking but not submitting or moving to the child page. Do you have an idea why is that ?. Thank you

Hi Gil,

This usually happens when the console has an error. You can try the following steps:

  1. Right click on the webpage
  2. Select Inspect
  3. Click on the Console tab
  4. Submit the form. You’ll probably see an error inside the Console—what does the error say?

Ian
Knack Pros

1 Like

Hey there: any chance I can get some help making this work? I am constantly getting a 400 error with this…

I have included my code and the 400 error from the console.

My two small edits that I know may exist: I moved authorization above the app ID as this is where knack suggests it in their documentation (although no impact on success) and the second save_Record_ID was having syntax issues (due to being save_Record_Id)

My Record ID field is field_2630 on object_59
Listened scene and view: scene_1282 view_1723
Save View and Scene: scene_1289 view_1723

Code Block:

// Function to Save Record ID
function save_Record_ID(recordID, scene_and_view, field_number) {
$.ajax({
url: “https://uscg-api.knack.com/v1/pages/” + scene_and_view + “/records/” + recordID,
type: “PUT”,
headers: {
“Authorization”: Knack.getUserToken()
“X-Knack-Application-Id”: Knack.application_id,
“X-Knack-REST-API-Key”: knack,

},
data: field_number,
tryCount: 0,
retryLimit: 3,
success: function(response) {
  console.log("Captured Record ID"); // Success Message in Console Log
  Knack.hideSpinner();
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
  this.tryCount++;
  let tryCount = this.tryCount, retryLimit = this.retryLimit, seconds; 
  if (tryCount <= retryLimit) { //try again
    switch(tryCount) {
      case 1:
      case 2: seconds = 5; break;
      case 3: seconds = 10; break; }
    let timeout = seconds * 1000;
    console.log("Error: " + XMLHttpRequest.status + " " + XMLHttpRequest.statusText + "\nRetry Count: " + tryCount + "\nRetrying in " + seconds + " seconds")
    let ajaxObject = this;
    window.setTimeout(function(){
      $.ajax(ajaxObject);
    }, timeout);
  } else {
    console.log("Failed to Capture Record ID");
  }
}

});
}

// Listens for record creation and saves the record id when record is created.
$(document).on(‘knack-record-create.view_1723’, function(event, view, record) { // UPDATE the view number to the form used to create a record
const field_number = {field_2630 : record.id}; // UPDATE the field number to the field used for storing the record id
const scene_number = “scene_1289”; // UPDATE to the scene number for the form used to save the record id
const view_number = “view_1744”; // UPDATE to the view number for the form used to save the record id
save_Record_ID(record.id, scene_number + “/views/” + view_number, field_number);
});

// This is the separate edit form used to save the record id
// This removes the view from HTML upon rendering to prevent data manipulation.
$(document).on(‘knack-view-render.view_1744’, function (event, view, record) {
$(‘#’ + view.key).remove();
});

400 error details from Console

  1. Request URL:

https://uscg-api.knack.com/v1/pages/scene_1289/views/view_1744/records/62fe8ebce2dc890021d50c3c

  1. Request Method:

PUT

  1. Status Code:

400 Bad Request

  1. Remote Address:

Redacted

  1. Referrer Policy:

strict-origin-when-cross-origin

  1. Response HeadersView source

  2. access-control-allow-credentials:

true

  1. access-control-allow-origin:

https://lsusrec.knack.com

  1. cache-control:

no-cache, no-store, must-revalidate

  1. Connection:

keep-alive

  1. Content-Length:

79

  1. Content-Type:

text/html; charset=utf-8

  1. Date:

Thu, 18 Aug 2022 19:10:54 GMT

  1. etag:

W/“4f-OxgdVXQQyjKuwzGQOcAH8+ms3VY”

  1. pragma:

no-cache

  1. server:

envoy

  1. set-cookie:

connect.sid=s%3Ae7vE1NIq4chRuvesObSCVnEtUGF3mtZe.k%2FYsATDkjkB9orXZ3ZU2JjEaqfAv4CY8JDTVdvFXHPo; Domain=knack.com; Path=/; HttpOnly; Secure; SameSite=None

  1. strict-transport-security:

max-age=31536000; includeSubDomains

  1. vary:

Origin, Accept-Encoding

  1. x-content-type-options:

nosniff

  1. x-envoy-upstream-service-time:

225

  1. x-frame-options:

‘allow-from’ https://uscg-api.knack.com

  1. x-request-id:

62fe8ebe4302cf0021ba477d

  1. x-xss-protection:

0

  1. Request HeadersView source

  2. Accept:

3./*

  1. Accept-Encoding:

gzip, deflate, br

  1. Accept-Language:

en-US,en;q=0.9

  1. Authorization:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiNjJmMmQyN2UwYmU4ZjYwMDIxNTU5YjM2IiwiYXBwbGljYXRpb25faWQiOiI2MmVkMzhjMjc0NjE0MTAwMjFmYTc0OGMiLCJpYXQiOjE2NjA4NDEzMzd9.QqzegimH9C8wTC4gXy4kPHQb_jZ0bzgu50Hqsw2FWrU

  1. Connection:

keep-alive

  1. Content-Length:

24

  1. Content-Type:

application/x-www-form-urlencoded; charset=UTF-8

  1. Host:

uscg-api.knack.com

  1. Origin:

https://lsusrec.knack.com

  1. Referer:

https://lsusrec.knack.com/

  1. sec-ch-ua:

“Chromium”;v=“104”, " Not A;Brand";v=“99”, “Google Chrome”;v=“104”

  1. sec-ch-ua-mobile:

?0

  1. sec-ch-ua-platform:

“Windows”

  1. Sec-Fetch-Dest:

empty

  1. Sec-Fetch-Mode:

cors

  1. Sec-Fetch-Site:

same-site

  1. User-Agent:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36

  1. X-Knack-Application-Id:

Redacted

  1. X-Knack-REST-API-Key:

knack

@Austin - I try to avoid JS wherever I can in Knack - so I circle you back to my comment above about doing this with Integromat. It’s very simple to set up and in my view Integromat is an essential tool to accompany Knack for a whole range of automations. See my blog for more examples:

Hime this helps!

I appreciate the reply, and I think my life would be much easier with some add-on. Sadly, this is a government contract and Make/Integromat does not comply with the regulatory approval process currently.

1 Like

@Austin

This might be worth checking out—Make has an OEM version that operates under stricter compliance and security standards.

The details are here: Make OEM

Robert, not sure if you are likely to see this, but I’m after some additional advice. I’ve got this working, sort of. My 'second form" (the one that saves the record id) is a child page of the create form, and yes it saves the record id, but then it just does nothing. I have set up a submit rule on that page to return to the parent page but it never gets there - after it submits it just sits there. I’ve tried other submit rules (such as redirecting to a new page, and redirecting to an existing page) but nothing works. is there something im missing?