The following HTML content sets up a container for the table.
The following JavaScript content performs two primary functions:
- Select all the documents where the document type is map.
- Retrieve the
ft:lastEditionmetadata values for each document.
The following JavaScript example relies on:
- The Clustered search web service
- The API access JavaScript method.
To add the same Custom component:
-
In the HTML panel, copy and paste the following:
<div id="result"> <table id="result_table"> <thead> <tr> <th>Type</th> <th>Title</th> <th>Last edition</th> </tr> </thead> <tbody> </tbody> </table> </div> <div id="result_paging"></div> -
In the CSS panel, copy and paste the following:
div#result { margin:0px; width:100%; } table#result_table { border: 1px solid black; border-collapse: collapse; } table#result_table td, #result_table th { border: 1px solid black; padding: 15px 5px; } table#result_table th { background-color:#E8ECEF; } div#result_paging { margin-top: 10px; } div#result_paging a, div#result_paging span { border: 1px solid #000; border-radius: 10px; padding: 5px; } -
In the JS panel, copy and paste the following:
(async () => { const FTAPI = await new window.fluidtopics.FluidTopicsApi(); FTAPI["Ft-Calling-App"] = "page-designer"; let allResults = []; // Store all the fetched results let currentPage = 1; // Initialize the current page of the table const resultsPerPage = 10; // Number of results to display per page of the table /********* Search Request **********/ async function fetchResults() { let body = { "filters": [{ 'key': 'ft:editorialType', values: ['book'] }], "paging": { "perPage": 50 } }; try { let apiMaps = await FTAPI.post('/api/khub/clustered-search', body); allResults = apiMaps.results.map(result => { let entry = result.entries[0]; return { 'type': entry.type, 'url': entry.map.readerUrl, 'title': entry.map.title, 'metadata': entry.map.metadata }; }); displayResults(currentPage); } catch (error) { console.error('Error fetching search results:', error); } } /********* Metadata **********/ function get_metadata_value_by_key(metas, key) { let o = metas.find(e => e.key === key); return (o === undefined ? '' : o.values.join(', ')); } /********* Results Display **********/ function displayResults(page) { // Calculate start and end indices for slicing the results const start = (page - 1) * resultsPerPage; const end = start + resultsPerPage; const paginatedResults = allResults.slice(start, end); let tbody = document.querySelector("#result_table tbody"); tbody.innerHTML = ""; // Clear previous results from tbody paginatedResults.forEach(r => { let row = tbody.insertRow(); let cell = row.insertCell(); cell.innerHTML = r.type; cell = row.insertCell(); cell.innerHTML = `<a href="${r.url}">${r.title}</a>`; cell = row.insertCell(); cell.innerHTML = get_metadata_value_by_key(r.metadata, 'ft:lastEdition'); }); // Pagination let div_paging = document.getElementById("result_paging"); div_paging.innerHTML = ""; // Clear previous pagination if (currentPage > 1) { let prevButton = document.createElement('button'); prevButton.innerText = 'Prev'; prevButton.onclick = () => { if (currentPage > 1) { currentPage -= 1; displayResults(currentPage); } }; div_paging.appendChild(prevButton); } let total_pages = Math.ceil(allResults.length / resultsPerPage); let pageInfo = document.createElement('span'); pageInfo.innerText = `${currentPage}/${total_pages}`; div_paging.appendChild(pageInfo); if (currentPage < total_pages) { let nextButton = document.createElement('button'); nextButton.innerText = 'Next'; nextButton.onclick = () => { if (currentPage < total_pages) { currentPage += 1; displayResults(currentPage); } }; div_paging.appendChild(nextButton); } } // Initial fetch fetchResults(); })(); -
Save the component.
-
Save and publish the page.