Filter connection field with another connection field

When I have 2 related connection fields (Let’s call them Projects and Tasks) that do have a parent/child relationship, and I’m using those 2 connection fields on a form, I would like the following:

  • If parent field is populated, I want the the child field to be filtered where only the children of the parent task can be selected
    • i.e., Project is filled, and I only want to be able to see and select related Tasks
  • If a child field is populated, I want the parent field to be defaulted with the child’s parent
    • i.e., Task is filled, and I want Project to automatically be filled with the Tasks’s parent Project. Also disable Project

I haven’t yet been able to figure out how to do adaptive filtering (besides the logged in user), and it’s greatly limiting my abilities to show the data I want to show

Any thoughts?

This would also be incredibly useful on the Search Component, not just forms

this might help

https://community.tadabase.io/t/multi-step-validation-or-population-of-select-options-based-on-user-input/2043/2

1 Like

Thanks Shumon!

Hi Josh, the first bullet is definitely possible, you can filter the child field based on the parent selection. But the second is not possible, since the child field won’t show anything until the parent field is selected.

If you can elaborate and maybe include some screen shots of what you’re trying to do, there might be a way using form rules, table rules, or pipes, but I’m not sure I’m understanding completely how you have it set up and what you want it to do.

1 Like

@Kristen is right, but regarding last part of second bullet this might help.

1 Like

@Josh_Yellowtail are you enjoying the journey Joshua?

have a look at this, login and view on full screen mode. What do you reckon?
https://templates.tadabase.io/standard.model/login

1 Like

Hi Kristen!

Yes, I’m finding that to be true, that if using the dependent dropdown feature, the parent record must be selected before choosing a child record.

My hope was to allow an open search for the child unless the parent was filled, then it would be filtered. And if doing an open search for a child, then if a child is selected, the parent would be auto-filled.

This would also be great in a Search Component to have dependent dropdown functionality

That page is looking great!

add filters as shown below OR you can add a search component at top of page, you’ll have to go through the tutorial files to understand the search component.

1 Like

I found documentation for a Filtered Join Record Selector plugin. I’m wondering if this might be able to accomplish my scenario where if a child is populated, then filter for the exact parent of that child.

Filtered Join Record S… | Plugins (tadabase.io)

And this might solve my scenario of defaulting the parent field with the parent assigned to the child

Set Connection Field v… | Plugins (tadabase.io)

I’m going to move this post into the App Development category. You may get more views and more feedback from other users there.

This category is for suggesting ideas to the development team and collecting votes from other users to support your idea, which might be why you aren’t getting the advice you’re looking for.

1 Like

Ok, finally figured out how to auto-populate the parent field when a child field is populated. Below is a template. Instructions are below the code. Any suggestions to modifying this would be greatly appreciated!

TB.render('component_X', function(data) {
    // Listen for changes in the Child table field (replace 'field_block_child' with the actual ID for the Child table field)
    jQuery('#field_block_child select.select2', data.ele).on('change', function() {
        var selectedChildId = jQuery(this).val(); // Get the selected Child table ID

        if (selectedChildId) {
            // Use Tadabase API with authentication to fetch related Parent table data (replace 'child_table_id' with actual Child table ID)
            jQuery.ajax({
                url: 'https://api.tadabase.io/api/v1/data-tables/child_table_id/records/' + selectedChildId, 
                method: 'GET',
                headers: {
                    'X-Tadabase-App-ID': 'YOUR_APP_ID',         // Replace with your Tadabase App ID
                    'X-Tadabase-App-Key': 'YOUR_API_KEY',       // Replace with your Tadabase API Key
                    'X-Tadabase-App-Secret': 'YOUR_API_SECRET', // Replace with your Tadabase API Secret
                },
                success: function(response) {
                    console.log('Full API Response:', response);  // Log the full API response for debugging

                    // Check if the Parent table field is available in the response (replace 'field_parent' with the actual Parent table field ID)
                    if (response && response.item && Array.isArray(response.item.field_parent) && response.item.field_parent.length > 0) {
                        var relatedParentId = response.item.field_parent[0]; // Get the first related Parent table ID
                        console.log('Related Parent Table ID:', relatedParentId);    // Log the related Parent table ID for debugging

                        // Populate the Parent table field (replace 'field_block_parent' with the actual ID for the Parent table field)
                        var parentField = jQuery('#field_block_parent 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 } }
                        });
                    } else {
                        console.log('No related Parent table data found.');
                    }
                },
                error: function(error) {
                    console.log('Error fetching related Parent table data:', error);
                    alert('There was an error fetching the related Parent table data. Please check the API key, table ID, and field mappings.');
                }
            });
        } else {
            console.log('No Child table data selected.');
        }
    });
});

Instructions for Using the Template:

  1. Replace component_X: Replace component_X with the actual Tadabase component ID where the fields are present (e.g., component_3).
  2. Replace field_block_child and field_block_parent:
  • field_block_child: Replace with the actual field block ID for your Child table field (where the user selects an entry from the Child table).
  • field_block_parent: Replace with the actual field block ID for your Parent table field (which you want to auto-populate based on the Child table).
  1. Replace child_table_id: Replace this with the actual ID of the Child table in your Tadabase app.
  2. Replace API credentials:
  • YOUR_APP_ID: Replace with your actual Tadabase App ID.
  • YOUR_API_KEY: Replace with your actual Tadabase API Key.
  • YOUR_API_SECRET: Replace with your actual Tadabase API Secret.
  1. Replace field_parent: Replace field_parent with the correct field ID for the Parent table connection field in the Child table (e.g., field_55).

What It Does:

  • This template listens for changes in the Child table field.
  • When a Child table entry is selected, it fetches the related Parent table field from the Child table using the Tadabase API.
  • It then auto-populates the Parent table field on the form with the corresponding value, without requiring the user to submit the form.

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.
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.