I currently have built a search bar with a table that lists out data. I am trying to match each word or letter in the search query and highlight the words accordingly. Here is an example:
Currently I understand how to achieve this with the UI but I am having issues with the logic and am a bit stuck.
Right now I am just trying to loop through each entry in the table, and simple match that customer field with the text in the Search Bar.
So far, as I am looping through each entry, I am seeing if a word in that entry is a match by doing this:
bool match = this.wordsToHighlight.any((ele) => entry.value.contains(ele));
if it's a match then I am looping through each word in the search query and matching them via regex like so:
for(final entry in item.entries) {
// for each entry return words to highlight
// does this word have any of the query words in it?
bool match = this.wordsToHighlight.any((ele) => entry.value.contains(ele));
if(match) {
// highlight the words that match and return that string
var textSpans = [];
for(final word in wordsToHighlight) {
var result = entry.value.toString().replaceAllMapped(RegExp('[\<t\>]$word', caseSensitive: false), (match) => '<t>${match.group(0)}</t>');
print('Result: $result');
}
}
I am surrounding each match in a sort of like HTML. I am just trying to visually see the text that I want to add highlights to be wrapped correctly for each matching word from the search query. (This isn't my solution, just trying to see visually in debug terminal)
I made a mini POC and it looks like this:
If I type in 280 So uff it gives me these results:
<t>280</t>083 Some Stuff
28083 <t>So</t> Stuff
28083 Some St<t>uff</t>
It's sort of working but as you can see I'm looping each query word and doing a regex on the entry column. Ideally I'd like to have this as my result:
<t>280</t>83 <t>So</t>me St<t>uff</t>
Just to be clear, the reason I'm adding the tags is to just see it working in the console for now. Eventually I want to use a RichText / TextSpan widget to add background color to the text, but I just need to get the matches right before I do this.
How is it possible to match the search bar query to get the correct results I am looking for? Hopefully someone can help please! Thank you!
Full Source Code for my simple POC:
class MyHomePage extends StatefulWidget {
const MyHomePage({ Key? key }) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final _controller = TextEditingController();
List<String> wordsToHighlight = [];
void search(String query) {
setState(() {
wordsToHighlight = query.split(" ");
});
}
@override
Widget build(BuildContext context) {
print(wordsToHighlight);
return Scaffold(
body: SafeArea(
child: Column(
children: [
SearchWidget(
textEditingController: _controller,
onChangeCallback: (val) => search(val),
clearTextCallback: () {
_controller.clear();
setState(() {
wordsToHighlight.clear();
});
},
),
const SizedBox(height: 50),
Expanded(
child: ListView.builder(
itemCount: mockData.length,
itemBuilder: (context, index) {
final item = mockData[index];
for(final entry in item.entries) {
// for each entry return words to highlight
// does this word have any of the query words in it?
bool match = this.wordsToHighlight.any((ele) => entry.value.contains(ele));
if(match) {
// highlight the words that match and return that string
var textSpans = [];
for(final word in wordsToHighlight) {
var result = entry.value.toString().replaceAllMapped(RegExp(word, caseSensitive: false), (match) => '<t>${match.group(0)}</t>');
print('Result: $result');
}
}
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 5),
child: Row(
children: [
for(final item in item.entries)
Expanded(
child: Text(item.value),
)
],
),
);
},
),
)
],
),
),
);
}
}
CodePudding user response:
You can use dynamic_text_highlighting package instead of default Text widget
to highlight the words.
Widget buildDTH(String text, List<String> highlights) {
return DynamicTextHighlighting(
text: text,
highlights: highlights,
color: Colors.yellow,
style: TextStyle(
fontSize: 18.0,
fontStyle: FontStyle.italic,
),
caseSensitive: false,
);
}
`
void applyChanges(List<String> newHighlights) {
setState(() {
highlights = newHighlights;
});
}