I’ve modified this further, and I’ve accomplished everything that I was looking to do.
Functionality:
- if parent field is populated, filter child field options
- if child field is populated, default parent field with the child’s parent
- if parent field is empty, allow any child to be selected
I ended up using a combination of the Tadabase Rest API pipe, PipeScripts, and Javascript.
With the Tadabase RestAPI pipe, I used the Get All Records, Get A Single Record, and Filter by a Connected ID Value calls.
TB.render('component_3', function(data) {
// Flags to prevent infinite loops
var isUpdatingParent = false;
var isUpdatingChild = false;
// Pipe keys
var getChildRecordsPipeKey = 'PIPE_KEY_FOR_FILTERED_PROJECTS'; // Replace with your actual pipe key
var getAllProjectsPipeKey = 'PIPE_KEY_FOR_ALL_PROJECTS'; // Replace with your actual pipe key
var getChildRecordPipeKey = 'PIPE_KEY_FOR_GET_CHILD_RECORD'; // Replace with your actual pipe key
// Function to load Child options based on Parent ID
function loadChildOptions(parentId) {
var childField = jQuery('#field_block_field_78 select.select2', data.ele);
// Capture original Select2 options and classes
var originalSelect2Options = childField.data('select2') ? childField.data('select2').options.options : {};
var originalClasses = childField.attr('class');
// Destroy existing select2 instance if initialized
if (childField.hasClass('select2-hidden-accessible')) {
childField.select2('destroy');
}
// Clear existing options
childField.empty();
// Add an empty option
childField.append('<option></option>');
if (parentId) {
// Prepare input variables for the pipe to get filtered projects
var inputVariables = {
ChildTableId: 'eykNOvrDY3', // Projects table ID
ParentRecordId: parentId,
ParentFieldChildTable: 'field_55' // Field in Projects table that references Ideas table
};
// Call the pipe to get child records filtered by Parent ID
TB.triggerPipe(getChildRecordsPipeKey, inputVariables, function(type, response) {
processChildRecords(type, response, childField, originalSelect2Options, originalClasses);
});
} else {
// Call the pipe to get all projects
TB.triggerPipe(getAllProjectsPipeKey, {}, function(type, response) {
processChildRecords(type, response, childField, originalSelect2Options, originalClasses);
});
}
}
// Function to process child records and update the Child field options
function processChildRecords(type, response, childField, originalSelect2Options, originalClasses) {
if (type === 'success' && response && response.items) {
var items = response.items;
if (items.length > 0) {
items.forEach(function(item) {
var childId = item.id;
var childName = item['field_46']; // Replace with your display field
// Add option to the select field
childField.append('<option value="' + childId + '">' + childName + '</option>');
});
} else {
console.log('No Child records found.');
}
// Re-add the original classes
childField.attr('class', originalClasses);
// Re-initialize select2 with original options
childField.select2(originalSelect2Options);
// Set the flag to prevent triggering the change event
isUpdatingChild = true;
// Trigger change event
childField.trigger('change');
// Reset the flag after a brief delay to ensure event handlers have completed
setTimeout(function() {
isUpdatingChild = false;
}, 100);
} else {
console.log('Error fetching Child records:', response);
alert('There was an error fetching the Child records.');
}
}
// Function to set Parent field based on selected Child
function setParentFieldFromChild(childId) {
if (childId) {
// Prepare input variables for the pipe
var inputVariables = {
tableId: 'eykNOvrDY3', // Projects table ID
recordID: childId
};
// Call the pipe to get child record
TB.triggerPipe(getChildRecordPipeKey, inputVariables, function(type, response) {
if (type === 'success' && response && response.item) {
var parentIds = response.item.field_55;
if (Array.isArray(parentIds) && parentIds.length > 0) {
var relatedParentId = parentIds[0];
// Set the flag to prevent triggering the change event
isUpdatingParent = true;
// Populate the Parent field
var parentField = jQuery('#field_block_field_77 select.select2', data.ele);
jQuery(parentField).val(relatedParentId).trigger('change.select2');
// Trigger the select2 select event
jQuery(parentField).trigger({
type: 'select2:select',
params: { data: { id: relatedParentId } }
});
// Reset the flag after a brief delay
setTimeout(function() {
isUpdatingParent = false;
}, 100);
} else {
console.log('No related Parent found.');
}
} else {
console.log('Error fetching Child record:', response);
alert('There was an error fetching the Child record.');
}
});
} else {
// Clear the Parent field if no Child is selected
var parentField = jQuery('#field_block_field_77 select.select2', data.ele);
// Set the flag to prevent triggering the change event
isUpdatingParent = true;
jQuery(parentField).val(null).trigger('change.select2');
// Trigger the select2 clear event
jQuery(parentField).trigger({
type: 'select2:unselect'
});
// Reset the flag after a brief delay
setTimeout(function() {
isUpdatingParent = false;
}, 100);
}
}
// Event listener for when Child field changes
jQuery('#field_block_field_78 select.select2', data.ele).on('change', function() {
if (isUpdatingChild) return;
var selectedChildId = jQuery(this).val(); // Get the selected Child ID
setParentFieldFromChild(selectedChildId);
});
// Event listener for when Parent field changes
jQuery('#field_block_field_77 select.select2', data.ele).on('change', function() {
if (isUpdatingParent) return;
var selectedParentId = jQuery(this).val(); // Get the selected Parent ID
loadChildOptions(selectedParentId);
});
// Initial load when the form renders
var initialParentId = jQuery('#field_block_field_77 select.select2', data.ele).val();
loadChildOptions(initialParentId);
// Initial set of Parent field if Child field has a value
var initialChildId = jQuery('#field_block_field_78 select.select2', data.ele).val();
setParentFieldFromChild(initialChildId);
});
Detailed Steps
1. Obtain Your API Credentials
- Navigate to Tadabase API Settings:
- Log in to your Tadabase account.
- Go to the Settings section and find the API Keys or API Credentials area.
- Copy Your Credentials:
- App ID: Copy your Tadabase App ID.
- App Key: Copy your Tadabase App Key.
- App Secret: Copy your Tadabase App Secret.
- Replace Placeholders:
- In the code, replace
'YOUR_APP_ID'
, 'YOUR_APP_KEY'
, and 'YOUR_APP_SECRET'
with your actual credentials.
2. Identify Component and Field Block IDs
- Component ID:
- Find the component where you want this script to run (e.g., a form component).
- The component ID can often be found in the component’s settings or URL.
- Replace
'component_YOUR_COMPONENT_ID'
with your actual component ID (e.g., 'component_3'
).
- Field Block Selectors:
- Parent Field:
- In your form, locate the parent field (e.g., a dropdown referencing the parent table).
- Inspect the element or check the field’s settings to find the field block ID (e.g.,
'field_block_field_77'
).
- Replace
'field_block_field_PARENT_FIELD_BLOCK_ID'
with your parent field block ID.
- Child Field:
- Locate the child field in your form.
- Find its field block ID (e.g.,
'field_block_field_78'
).
- Replace
'field_block_field_CHILD_FIELD_BLOCK_ID'
with your child field block ID.
3. Find Table and Field IDs
- Child Table ID:
- Go to the Data Builder in Tadabase.
- Select your child table (e.g., Projects table).
- The table ID is usually visible in the URL or table settings (e.g.,
'eykNOvrDY3'
).
- Replace
'YOUR_CHILD_TABLE_ID'
with your child table ID.
- Parent Field ID in Child Table:
- In the child table, identify the field that references the parent table (e.g., a connection field).
- Find the field ID (e.g.,
'field_55'
).
- Replace
'YOUR_PARENT_FIELD_ID_IN_CHILD_TABLE'
with this field ID.
- Child Display Field ID:
- Decide which field in the child table you want to display in the dropdown (e.g.,
'Project Name'
).
- Find the field ID (e.g.,
'field_46'
).
- Replace
'YOUR_CHILD_DISPLAY_FIELD_ID'
with this field ID.
4. Insert the Code into Tadabase
- Access the JavaScript Section:
- In your Tadabase application, navigate to the page or component where you want to add the script.
- Go to the JavaScript section for that page or component.
- Paste the Code:
- Copy the entire template code provided above.
- Paste it into the JavaScript section.
- Double-Check Placeholders:
- Ensure all placeholders have been correctly replaced with your actual IDs and credentials.
5. Test the Functionality
- Refresh the Page:
- Open the page containing the form and refresh it to ensure the script is loaded.
- Test Parent to Child Filtering:
- Select a value in the parent field.
- Verify that the child field updates to show only the related records.
- Test Child to Parent Auto-Population:
- Select a value in the child field.
- Verify that the parent field auto-populates with the corresponding parent record.
- Test Empty Parent Field:
- Clear the parent field.
- Verify that the child field shows all available records.
6. Troubleshooting
- Check the Console:
- Open your browser’s developer console to check for any error messages.
- Look for logs that indicate issues with fetching records or any undefined variables.
- Verify Field and Table IDs:
- Ensure that all field and table IDs are correct and correspond to your Tadabase application.
- API Credentials:
- Confirm that your API credentials are valid and have the necessary permissions to access the data.
7. Security Considerations
- Protect API Credentials:
- Avoid exposing your API credentials in publicly accessible code.
- Consider using server-side scripts or Tadabase’s built-in security features to handle sensitive operations.
- Limit API Access:
- Use API keys with limited permissions when possible.
- Regularly rotate your API credentials and monitor for any unauthorized access.
Additional Notes
- Select2 Library:
- The script assumes that the Select2 library is being used for dropdown fields.
- Ensure that Select2 is properly initialized in your form.
- Dependencies:
- The script uses jQuery for DOM manipulation and AJAX requests.
- Make sure jQuery is included in your application.
- Customization:
- You can modify the script to fit additional requirements, such as handling multiple parent-child relationships or adding custom filters.
- Performance Considerations:
- For tables with a large number of records, consider implementing pagination or limiting the number of records fetched to improve performance.