I am certain there’s a way to do this, but searching and Googling hasn’t been fruitful thus far! When selecting a Name in a Searchable field, I’d like to display some other fields from the same record over to the right after it’s been selected, but before any other action is taken. Example form attached. Any ideas?? Thanks!
Is this an Add or Edit form you’re showing?
I presume you want to show more than the patient name ?
This is an add form. Yes, once the Patient name is searched for and selected, i’d like it to populate some related connected other Fields to display dynamically as well, (the Product and Quantity fields).
I’ve been fooling with this for HOURS with ChatGPT and i keep running into roadblocks related to the API call authentication. I’m getting blocked by CORS. My API call in the Console logs does this:
GET https://us-gov-west-1-renderer.knack.com/v1/objects/object_35/records/xxxxxxxxxxxxxx net::ERR_FAILED 403 (Forbidden)
I can post the entire code ChatGpt came up with if thats helpful as a starting point?
Here’s the latest iteration of code that AI has helped me come up with, that is getting blocked on the API call:
/********************
- CONFIGURATION
********************/
const sceneKey = “scene_890”; // Scene key
const viewKey = “view_2807”; // View key
const connectionFieldKey = “field_760”; // Connection field key
const connectedObjectKey = “object_35”; // Connected Object key
const displayFields = [“field_1014”, “field_1822”]; // Fields to fetch and display
const knackBaseUrl ="https://us-gov-west-1-renderer-read.knack.com/v1"
; // Government server based URL
/********************
- EVENT: Scene Render
********************/
$(document).on(knack-scene-render.${sceneKey}
, function () {
console.log(Scene ${sceneKey} rendered.
);
// Poll for the View to appear in the DOM
const pollInterval = 100; // Check every 100ms
const maxRetries = 50; // Check up to 5 seconds (50 retries)
let retries = 0;
const interval = setInterval(() => {
const $view = $(#${viewKey}
);
if ($view.length > 0) {
console.log(`View ${viewKey} found.`);
clearInterval(interval); // Stop polling
initializeFormView($view);
} else if (++retries >= maxRetries) {
console.error(`View ${viewKey} not found after ${maxRetries} attempts.`);
clearInterval(interval);
}
}, pollInterval);
});
/********************
- FUNCTION: Initialize Form View
********************/
function initializeFormView($view) {
console.log(“Initializing form view…”);
// Dynamically locate the dropdown for the Connection field
const $connectionFieldSelect = $view.find(select[name="${connectionFieldKey}"]
);
if ($connectionFieldSelect.length === 0) {
console.error(Connection dropdown for field '${connectionFieldKey}' not found in view ${viewKey}.
);
return;
}
console.log(Connection dropdown '${connectionFieldKey}' found in view '${viewKey}'.
, $connectionFieldSelect);
// Create the container for displaying additional information
let $container = $view.find(‘#display-container’);
if ($container.length === 0) {
$container = $(‘
$connectionFieldSelect.closest(‘.kn-input’).after($container);
console.log(“Container created and added to the DOM.”);
}
// Attach a change event listener to the dropdown
$connectionFieldSelect.on(‘change’, async function () {
const selectedRecordId = $(this).val(); // Get selected record ID from the dropdown
console.log(Connection field value changed. Selected record ID: ${selectedRecordId}
);
// If no record is selected, clear the container
if (!selectedRecordId) {
console.log("No record selected. Clearing container.");
$container.html("");
return;
}
// Check if the user is authenticated
const userToken = Knack.getUserToken();
if (!userToken) {
console.error("User is not authenticated. Cannot fetch data.");
$container.html("<p style='color: red;'>You are not authenticated. Please log in to view this information.</p>");
return;
}
// Fetch the connected record using the current user's session token
try {
console.log(`Fetching record ${selectedRecordId} from object ${connectedObjectKey}...`);
const response = await fetch(`${knackBaseUrl}/objects/${connectedObjectKey}/records/${selectedRecordId}`, {
method: "GET",
headers: {
'X-Knack-Application-Id': Knack.application_id,
'Authorization': userToken, // User token for secure access
},
});
if (!response.ok) {
throw new Error(`API error: ${response.statusText}`);
}
const record = await response.json();
console.log("Fetched record:", record);
// Display the fetched fields in the container
let displayHTML = `<h4>Additional Information:</h4>`;
displayFields.forEach((fieldKey) => {
if (record[fieldKey]) {
displayHTML += `<p><strong>${fieldKey}:</strong> ${record[fieldKey]}</p>`;
}
});
$container.html(displayHTML); // Insert the HTML into the container
console.log("Additional information displayed.");
} catch (error) {
console.error("Error fetching connected record:", error);
$container.html("<p style='color: red;'>Error loading additional information.</p>");
}
});
}Preformatted text
I’m not a coder and there is no native solution in Knack to dynamically show related data in an add form. Hopefully someone else can help you that has some coding skills.
@JDWorleyKY ChatGPT doesn’t always have the context, and sometimes complicates it more unfortunately!
Here’s a simpler solution. In my example, I get the connected record’s phone and email values and add them to other field inputs on the same form. You may want to display them somewhere else, but that’s up to you!
It would be too wordy to detail the step-by-step on how to install, but here’s a summary:
- It loads the Knack API Helper library for a simplified view-based API call (credit to Callum Boase)
- On render of
view_xx
form:- Detect change of selection to
field_aa
connection field - Get the Patient record from a
scene_xx
/view_yy
details view that the logged-in user can access - Update
field_bb
/field_cc
with values fromfield_xx
/field_yy
- Detect change of selection to
Please message me privately if you’d like some help installing!
loadExternalFiles([
{ type: 'script', module: false, url: 'https://cdn.jsdelivr.net/npm/knack-api-helper@latest/browser.js' }, // Knack API Helper - https://socket.dev/npm/package/knack-api-helper
]);
$(document).on(`knack-view-render.view_xx`, async function (event, view, data) {
const patientField = 'field_aa';
// When the connection value changes...
$(`#${view.key}-${patientField}`).on('change', async function() {
const recordId = $(this).val(); // Get the selected record ID
if (recordId) { // If a selection is made...
const record = await KnackAPI.makeRequest('get', {scene: 'scene_xx', view: 'view_yy', recordId: recordId}); // Get the patient record
// Update the form field inputs with new values
$(`#${view.key} #field_bb`).val(record?.field_xx_raw?.email || ''); // Email
$(`#${view.key} #field_cc`).val(record?.field_yy_raw?.number || ''); // Phone
}
});
});
//Generic helper function to loader external JS and CSS files before your Knack app finishes loading
function loadExternalFiles(externalFiles) {
// Insert code from here: https://app.lowcodemastery.com/#resource-public-view/66033c6ac88da60027fec12b/
}
I knew @StephenChapman would know
This seems pretty cool but its still a little above my head. I copied and pasted the code and fixed it to be all my views/keys, but its not working still due to the API: “Error fetching connected record: ReferenceError: KnackAPI is not defined”. I’ll message you Stephen, thanks!
Hi @JDWorleyKY,
Not sure if this is the full solution, but at least it’s getting you very close to one, without any code at all.
See the KTL’s feature called View Record Details.
It’s the _vrd keyword and can be found here, in a live demo for you to experiment with:
https://ctrnd.knack.com/ktl-tutorials#ktl-demo-page/
Currently, in that dynamic sub-view, there’s a link to “View All Details”, but it would be easy to have a link to edit the record as well.
You can find all documentation and setup instructions here: Keywords · cortexrd/Knack-Toolkit-Library Wiki
enjoy,
Normand D.
Got this to work, thanks so much @StephenChapman !!