Searching
Copying and pasting? We've got you covered! You can find the full source code of this tutorial here.
Searching Through Your Data 🔎
Developers who expose large datasets in a table need to let users quickly find specific rows — but implementing search that works across all columns, respects nested structure, and supports structured queries like "age greater than 30" or "job includes Manager" requires building a filtering engine from scratch.
The table component's query string system filters rows across all columns with a single property assignment, and supports structured query syntax for comparisons, inclusion checks, and compound conditions without any additional configuration.
This tutorial covers wiring a debounced text input to the table's query string for instant full-text search; toggling a preserve-structure flag to control whether nested rows stay grouped or are flattened in filtered results; writing structured queries using column, operator, and value syntax (equals, includes, less than, greater than, starts with); combining multiple conditions with the & operator; and wiring quick-filter buttons that preset the search box and query simultaneously.
By the end, you'll have a searchable nested table with full-text search, structured query support, preserve-structure toggle, and one-click quick filters.
🖖 Initializing the Library and Setting the Table
As always, let's first initialize the UI library. Remember you only have to do it once in your entire app.
// You have to import from "@thatopen/ui"
import * as BUI from "../../../..";
BUI.Manager.init();
Once you have initialized the library, you can create a new table or get an existing from your HTML document. For simplicity purposes, let's create one programatically:
type TableData = {
Name: string;
Age: number;
Job: string;
Company: string;
Bio: string;
};
const table = BUI.Component.create<BUI.Table<TableData>>(
() => BUI.html`
<bim-table expanded>
<div slot="missing-data" style="display: flex; flex-direction: column; align-items: center; width: 8rem; margin: auto;">
<bim-label>No data to display!</bim-label>
</div>
</bim-table>
`,
);
table.data = [
{
data: {
Name: "Juan Hoyos",
Age: 28,
Job: "BIM Software Developer",
Company: "That Open Company",
Bio: "Juan is a very cool guy, writing this tutorial so you know how to use a really powerful table in your projects",
},
children: [
{
data: {
Name: "Maria Lopez",
Age: 24,
Job: "Junior BIM Specialist",
Company: "That Open Company",
Bio: "Maria assists Juan in developing BIM solutions and learning the ropes of software development.",
},
},
{
data: {
Name: "Ana Garcia",
Age: 32,
Job: "Structural Engineer",
Company: "Skyline Structures",
Bio: "Ana is a meticulous engineer with a knack for ensuring that every project is structurally sound.",
},
children: [
{
data: {
Name: "Luis Herrera",
Age: 27,
Job: "BIM Software Developer",
Company: "Skyline Structures",
Bio: "Luis is Ana's right hand, assisting in design calculations and learning advanced structural modeling.",
},
},
],
},
],
},
{
data: {
Name: "Antonio Viegas",
Age: 30,
Job: "BIM Software Developer",
Company: "That Open Company",
Bio: "Antonio is the CEO of That Open Company. He is the author of @thatopen/fragments.",
},
children: [
{
data: {
Name: "Sara Jimenez",
Age: 30,
Job: "Assistant Project Manager",
Company: "BuildSmart Ltd.",
Bio: "Sara supports Carlos in project planning, client coordination, and schedule management.",
},
},
{
data: {
Name: "Tomas Rivera",
Age: 33,
Job: "Site Supervisor",
Company: "BuildSmart Ltd.",
Bio: "Tomas ensures that project sites run smoothly, handling logistics and on-site team coordination.",
},
},
],
},
];
🆎 Implementing a Search Box
When it comes to search data in a bim-table we have the powerful table.queryString. It is "just" a string property in the table component to filter the matching values. However, it goes beyond that 😉 Let's start by simply setting a text input to provide a value to the query string property as follows:
// You can search data in the table by providing a queryString
const searchBox = BUI.Component.create<BUI.TextInput>(() => {
const onInput = (e: Event) => {
const input = e.target;
if (!(input instanceof BUI.TextInput)) return;
table.queryString = input.value; // Here is where the magic happens!
};
return BUI.html`
<bim-text-input @input=${onInput} placeholder="Search..." debounce=250></bim-text-input>
`;
});
Basically that's it! The only thing you need is to provide a value to table.queryString and the rest is handled internally by the component. However, at this point a question arises: what happens with the nestings when you filter the data? Well, it depends on you! By default, when the table is filtered the nestings are removed; but, in case you prefer to keep the nesting structure, then you just have to activate the corresponding option. To better ilustrate this, let's implement a very simple checkbox to change the nesting structure behavior when searching:
const preserveStructure = BUI.Component.create(() => {
const onChange = (e: Event) => {
const input = e.target;
if (!(input instanceof BUI.Checkbox)) return;
// You just have to change the following flag in your table
table.preserveStructureOnFilter = input.checked;
};
return BUI.html`
<bim-checkbox @change=${onChange} label="Preserve Structure"></bim-checkbox>
`;
});
Assuming you're using the same data as in this tutorial, try searching Tomas with and without the Preserve Structure flag checked to notice the difference!
🆎 Advanced Searching (WIP)
So far, so good! We already have a functional search box for the table in the app. What's next? Well, you can leave it until here, but there is something more you should know about queryString... and that is you can use it to perform complex queries (thus the name). For example, what happens if you want to know which users in the table are older than 30 years old? Or to know who is a manager? Or maybe knowing if someone matches an specific keyword in the Bio? What about something more complex as people working as a BIM Software Developer in That Open Company? For all those cases, you can still use the exact same query string property without doing any special configuration in the table! The only difference is how you write the search.
In order to define a query, you need to specify the column to search through, then some condition, and finally the value to look at; in other words, the structure is [column][condition][value]. Optionally, you can concatenate multiple queries by using the & operator. Currently, the available conditionals are:
- Equals (=)
- Includes (?)
- Less Than (<)
- Less Than or Equals to (<=)
- Greater Than (>)
- Greater Than or Equals to (>=)
- Starts With (/)
So, with that in mind, try to do the following queries by yourself 👇
Age>30
Job?Manager
Job?Developer & Company=That Open Company
Cool, isn't? Also, is very simple yet powerful. Now, something really cool you can do knowing that is to do some quick filters for you end-users. Let's do it as follows:
const quickFilters = BUI.Component.create(() => {
const onManagersClick = () => {
const query = "Job?Manager";
table.queryString = query;
// We also update the search box to reflect the current query
searchBox.value = query;
};
const onDevelopersClick = () => {
const query = "Job?Developer";
table.queryString = query;
// We also update the search box to reflect the current query
searchBox.value = query;
};
return BUI.html`
<div style="display: flex; gap: 0.5rem">
<bim-button @click=${onManagersClick} label="Managers"></bim-button>
<bim-button @click=${onDevelopersClick} label="Developers"></bim-button>
</div>
`;
});
🔗 Putting Everything Together
As everything is already setup, let's create a new component to hold all everything and display them in the page. You can do it very easily like this:
const appContent = BUI.Component.create(
() => BUI.html`
<div style="display: flex; flex-direction: column; gap: 0.75rem; height: 100%;">
<div style="display: flex; gap: 0.75rem;">
${searchBox}
${quickFilters}
${preserveStructure}
</div>
${table}
</div>
`,
);
document.body.append(appContent);
Congratulations! You already know how to use an advanced feature of the bim-table component to display the information exactly how you need it. Don't hesitate into watching more tutorials! 🚀