The Preqin 2020 Private Capital Fund Terms Advisor Extract
Get an exclusive recap of last year's report ahead of the launch of The Preqin 2021 Private Capital Fund Terms Advisor!
Simply submit the form and download the extract straight away.
'); // Wrap in a container
$inputField.after('' +
decodeURI('%3Csvg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 20 20" class="search-icon">'))
// Find the container (assuming it's the direct parent with the class)
const $container = $inputField.closest('#formField--companyName');
// Demo display element
const $idDisplaySpan = $('#selected-id-display span');
let $resultsContainer = null;
let $resultsList = null;
let valueWasSelected = false; // Flag to track if the current value is from selection
let responseData = null; // Store the response data
// --- Helper Functions ---
function ensureResultsListExists() {
if(!$resultsContainer || $resultsContainer.length === 0) {
$resultsContainer = $container.find('.autocomplete-results');
if($resultsContainer.length === 0) {
$resultsContainer = $('
');
$resultsContainer.show();
}
currentRequest = null;
}
});
}
// Function to match company type from API to dropdown option
function setCompanyTypeFromAPI(apiCompanyType) {
if (!apiCompanyType || !$companyTypeField.length) {
return;
}
// First try exact match (most API types match dropdown options exactly)
let matchedOption = $companyTypeField.find('option').filter(function() {
return $(this).text().trim() === apiCompanyType;
});
// If no exact match, check for specific mappings for the differences
if (matchedOption.length === 0) {
const specificMappings = {
'Non-sponsor backed': 'Other', // API type not in dropdown
'Professional Services': 'Other', // API type not in dropdown
'Infrastructure - Other': 'Infrastructure - Other', // Check if this exact match works
'Natural Resources - Other': 'Natural Resources - Other', // Check if this exact match works
'Real Estate - Other': 'Real Estate - Other' // Check if this exact match works
};
if (specificMappings[apiCompanyType]) {
const mappedType = specificMappings[apiCompanyType];
matchedOption = $companyTypeField.find('option').filter(function() {
return $(this).text().trim() === mappedType;
});
}
}
// Set the matched option or clear if no match found
if (matchedOption.length > 0) {
$companyTypeField.val(matchedOption.first().val());
} else {
$companyTypeField.val('');
console.log(`No matching dropdown option found for API company type: "${apiCompanyType}"`);
}
}
// Function to handle selection (from click or Enter key)
function handleSelection($selectedItem) {
if(!$selectedItem || $selectedItem.length === 0 || $selectedItem.hasClass('autocomplete-message')) {
return; // Do nothing if no valid item or it's a message
}
const selectedText = $selectedItem.text();
const selectedId = $selectedItem.data('company-id'); // Retrieve stored ID
const selectedCompanyData = $selectedItem.data('company-data'); // Retrieve complete company data
if(selectedId) {
$inputField.val(selectedText); // Update visible input
$hiddenFirmIdInput.val(selectedId); // Update hidden input
// Update company type field if type exists in company data
if(selectedCompanyData && selectedCompanyData.typeRaw) {
setCompanyTypeFromAPI(selectedCompanyData.typeRaw);
} else {
$companyTypeField.val(''); // Clear if no type available
}
valueWasSelected = true; // Mark that selection occurred
$idDisplaySpan?.text(selectedId); // Update demo display
// console.log("Selected:", selectedText, "ID:", selectedId);
hideResults();
$inputField.trigger('change'); // Optional: Trigger change event for other listeners
}
else {
console.warn('Selected item missing company ID data:', $selectedItem);
hideResults(); // Hide results even if ID is missing
}
}
// --- Event Handlers ---
$inputField.on('input', function() {
const currentInputValue = $(this).val();
const searchTerm = currentInputValue.trim();
// CRITICAL: If the user types anything, clear the previously selected ID
// Only clear if the flag 'valueWasSelected' is true, meaning the last change
// wasn't already a manual input modification.
if(valueWasSelected) {
clearSelectedId();
}
// We always set valueWasSelected to false here, because *any* input
// event means the current value is potentially manual, until a selection happens again.
valueWasSelected = false;
clearTimeout(debounceTimer);
if(currentRequest) {
currentRequest.abort();
currentRequest = null;
}
if(searchTerm.length === 0) {
hideResults();
clearSelectedId(); // Also clear ID if input is emptied
return;
}
debounceTimer = setTimeout(() => {
performQuickSearch(searchTerm);
}, debounceDelay);
});
// Handle click on a suggestion item (delegated to container)
$container.on('click', '.autocomplete-results li', function(e) {
handleSelection($(this)); // Pass the clicked LI to the handler
});
// Keyboard navigation and selection/dismissal
$inputField.on('keydown', function(e) {
// Handle arrow-down when results are not visible - trigger search
if (e.key === 'ArrowDown' && (!$resultsContainer || !$resultsContainer.is(':visible'))) {
e.preventDefault();
const searchTerm = $(this).val().trim();
// If there's text in the input, trigger a search
if (searchTerm.length > 0) {
performQuickSearch(searchTerm, { autoSelectFirst: true });
}
return;
}
// Handle TAB key when results are not visible - allow normal focus movement
if (e.key === 'Tab' && (!$resultsContainer || !$resultsContainer.is(':visible'))) {
// Don't prevent default - allow normal tab navigation to next field
return;
}
if(!$resultsContainer || !$resultsContainer.is(':visible')) {
// If results not visible, ESC shouldn't do anything special here
return;
}
const $items = $resultsList.find('li:not(.autocomplete-message)');
if(!$items.length && e.key !== 'Escape') {
return;
} // No items to navigate (but allow ESC)
let $currentActive = $items.filter('.active');
let currentIndex = $items.index($currentActive);
switch(e.key) {
case 'ArrowDown':
e.preventDefault();
currentIndex = ($currentActive.length === 0) ? 0: (currentIndex + 1) % $items.length;
$items.removeClass('active');
$items.eq(currentIndex).addClass('active');
break;
case 'ArrowUp':
e.preventDefault();
currentIndex = ($currentActive.length === 0) ? $items.length - 1: (currentIndex - 1 + $items.length) % $items.length;
$items.removeClass('active');
$items.eq(currentIndex).addClass('active');
break;
case 'Enter':
e.preventDefault(); // IMPORTANT: Prevent form submission
if($currentActive.length) {
handleSelection($currentActive); // Use the selection handler
}
else {
// Optional: Hide results if Enter is pressed without a selection
hideResults();
}
break;
case 'Escape': // ESC key dismisses
e.preventDefault();
hideResults();
break;
case 'Tab': // Tab key dismisses and allows normal focus movement
hideResults();
// Don't prevent default - allow normal tab navigation to next field
break;
}
});
// Hide results when clicking outside
$(document).on('click', function(e) {
// Check if the click is outside the input AND outside the results container
if(!$inputField.is(e.target) && !$container.is(e.target) && $container.has(e.target).length === 0) {
if($resultsContainer && $resultsContainer.is(':visible')) {
hideResults();
}
}
});
// Initial state check (optional)
if($hiddenFirmIdInput.val()) {
$idDisplaySpan?.text($hiddenFirmIdInput.val());
valueWasSelected = true; // Assume pre-filled value was selected
}
});