Search Bar Functionality

Hello,

My company and I are currently building a website on wix, and we’ve created a page in our website that has a repeater and a search bar. We’ve watched some videos that show how to connect a repeater to a database, and how to set up a search bar: this is something that we have already completed. We’ve entered code into our website, and everything works as it should. In our databse collection, each item has a field in which there are a certain number of keywords. Via wix code, we’ve managed to have it so when you type one of these keywords, the items that have that keyword appear. However, we’ve noticed that when you type more than one keyword into the search bar nothing appears (unless the item that you are trying to see has those keywords typed in the database in the same way that you entered them into the search bar.

For example:

An item in our database has these keywords - Red Blue Yellow. If we type Red Yellow Blue (in this order) into the search bar this item doesn’t appear, although the keywords match. We have to type Red Blue Yellow, as it is exactly entered into our database for this item to appear.

We want to know if there is a way to have it so that when you type, say, Red Blue Yellow (in whatever order) into the search bar, all of the items in the database that have one, two, or all of those keywords appear. Moreover, we want to know if there is a way to have the items that appear ranked (the items that have 3 out of the 3 keywords that were entered into the search bar appear first, followed by the items that have 2 out of the 3 keywords that were entered into the search bar second, etc.

We’ve been in touch with Wix support already, and we were directed to this forum. We’ve watched many videos showing how to configure data in wix too.

Please help us. If you need me to be more clear about what it is that we are trying to do please let me know.

Thank you.

https://www.wix.com/corvid/reference/wix-data.WixDataQuery.html
https://www.wix.com/corvid/reference/wix-dataset.Dataset.html#setFilter

Hi givemeawhisky,

I appreciate your response.

Is there a simpler way of doing this? I don’t understand the purpose and context of the coding on the page that you provided.

It is possible, but the way to do it depends on your collection structure, the fields you have in your collection(s) and the way you implemented your code. There’s more than one way to achieve that, but in any case you’ll have to write some code.

Hi J. D.

Thanks for your response.

I’m not sure if this helps but this is the coding that I have on the page so far:

import wixData from “wix-data”;
$w.onReady( function () {
//TODO: write your page related code here…

});
let debounceTimer;
export function iikeyword_keyPress(event, $w) {
if (debounceTimer) {
clearTimeout(debounceTimer);
debounceTimer = undefined;
}
debounceTimer = setTimeout(() => {
filter($w(‘#ikeyword’).value);
}, 200);
}

let lastFilterTitle;
function filter(title) {
if (lastFilterTitle !== title) {
$w(‘#dataset1’).setFilter(wixData.filter().contains(‘keywords’, title));
lastFilterTitle = title;
}
}

First, a comment about your code - one time you called the input element iikeyword and the second time you called it ikeyword; Are they different elements?
Second, it’s not clear if the “keywords” field in your database is a simple string or an array of strings (or maybe something else).

In the properties tab of the search bar (user input) that I’ve inserted onto my page, iikeyword_keyPress is the name of the onKeyPress event. ikeyword is the ID that I’ve entered for that search bar (at the top of the properties tab).

keywords is a field in my dataset. I have 5 fields in total, and 16 items that have been entered into my dataset (going exactly by the Wix terminology here). Each item is going to have multiple keywords associated with it, which means that I am going to be entering multiple words into the keywords field in my dataset. All in all, I want the search bar to be able to show the items that have the keywords that are entered into the search bar by the user without specificity. Put simply, if an item has a keyword that has been entered into the search bar in whatever order, we want that item to appear. To answer your second question directly, I’m not sure what a simple string is or an array of strings.


Here’s a screenshot.

  1. It doesn’t make sense. The onKeyPress function refers to the same element that you’re trying to retrieve its value. they both should have the same property name.

  2. Are you going to insert keyword like “red blue yellow” (1 single string)? Or in a different format?

  1. Okay. I’ve changed the ID of the search bar to iikeyword so that the ID and the onKeyPress have the same name.
  2. We want the user to be able to insert keywords in any format into the search bar to display results (so we want an array of strings I guess). The problem is that right now, it is too specific. To see an item that has the keywords “red blue yellow,” you have to type that exactly into the search bar - “red blue yellow.” You cannot type “yellow blue red” and expect to see the same results.

Any way, you can read in this thread how to make such a search using the split() method to separate the words in the query and run them against a certain string.
Of course you’ll have to adjust it to filter and if you want to run it while typing yo’ll have to add the dbouncer.

https://www.wix.com/corvid/forum/community-discussion/how-does-hasall-and-hassome-work

See link above. as I said it’ll require some adjustments but the principles are there.

I’ve made the adjustments for you. I hope that would help:

import wixData from 'wix-data';
let searchWords, inputString, lastFilterTitle;

$w.onReady(function () {
    $w("#ikeyword").onKeyPress((event) => {
 let debounceTimer;
 if(debounceTimer) {
    clearTimeout(debounceTimer);
    debounceTimer = undefined;
} 
debounceTimer = setTimeout(() => {
     inputString = $w("#ikeyword").value;
searchWords = inputString.split(" ");
        runFilter(searchWords);
}, 200);

function runFilter(wordArray){
 let filterSetting = wixData.filter();
 for (let i=0; i < wordArray.length; i++) 
    {       
        filterSetting = filterSetting.contains('keywords', wordArray[i]);
    }  
 if (lastFilterTitle !== inputString) {
        $w('#dataset1').setFilter(filterSetting);
        lastFilterTitle = inputString;
    }
}
 
    })
});

Thanks J. D.

I’ve tried it out a few times, and it works perfectly.

On top of this, is there a way to have it so when you type keywords into the search bar, the results that appear are ranked? For instance - imagine that there is an item in the database that has the keywords “Green Orange Brown,” an item that has the keywords “Green Red Yellow,” and an item that has the keywords “Green Red Blue.” Right now, if you type “Green” into the search bar, all of the results appear. But once you type “Green Red Blue” into the search bar, the item that has the keywords “Green Red Yellow” and the item that has the keywords “Green Orange Brown” do not appear, although the former has two out of the three keywords that have been typed and the latter has one.

Is there a way to have it so when you type a certain amount of keywords into the search bar (could be one or 50), all of the items that are associated with each of those keywords appear in an order that is ranked The first item appearing having 50 out of the 50 keywords that were entered, and the last having one of the 50 keywords that were entered.

So you need OR not AND + sum up each match score.
It is possible, but more complicated and it’d take me too much time to write it, and I don’t have time for that.
Maybe someone else, can provide a quick solution.

Thanks a lot for your help J. D.!

You’re welcome.
If you want to write the code yourself, I think it’d better not to work with a dataset but directly with your collection and if your collection is small enough, maybe even to pull it all together and query the results with JavaScript to save the back-and-forth time.
But of course it’s significantly more complicated than what you have now.

Hi J. D.

You assisted me with my Wix code 2 - 3 weeks ago. I had a repeater that was connected to a dataset that was correctly set up. I wanted to have it so that when I typed a list of keywords into the search bar (in any order), the content that had those keywords appeard. My code had been incorrectly entered, and you provided me with the correct code to enter. After you helped me with this, I asked you if there was a way to have it so that the results that show when you type keywords are ranked based on relevance (i. e. the content that has 3 out of 3 keywords that have been entered appears first, the content that has 2 out of 3 keywords entered appears second, the content that has 1 out of 3 keywords entered appears last). You told me that it was possible to do this and you provided some suggestions.

I understand that you told me you are too busy to do this, but I was wondering if you would be willing to help with this here. I don’t know much about Javascript or Wix code.

Another question I have is this: Right now, when I type keywords that are affiliated with two separate entries into my search bar, nothing appears. For example, I have two entries in my dataset - “Bethesda” and “Victorian Revival.” For Bethesda, “Bethesda” is a keyword. For Victorian Revival, “Victorian” is a keyword. So when I type “Bethesda” and “Victorian” into my search bar, hoping to see both entries appear, nothing appears. It seems I need to have an entry that has these two keywords, “Bethesda” and “Victorian,” for something to appear. Is there a way to have it so that when you enter keywords into your search bar, all of the content that has any of those keywords appears?

Please let me know if you’re willing to help me.

How big is your collection? How many rows?

As of now, there are 16 rows in my collection. But there are going to be more in the future for sure. I’m trying to figure out how to put everything that we need together first before I add all of the entries that I need.

So if it’s small as you said, I think i would pull it alll together and run the search on the results.
I’m putting here some code (there might be mistakes but you can test it).

  • maybe others will have different solutions in mind;

Read the notations carefully

//General:
 ///1. On page load, I retrieve all items. It might take a few seconds (you can put a pre-loader if you want), but then the search itself will be fast;
 ////2. I didn't filter out anything, I just put the items of match === 0  at the end of the results. It's not difficult to filter out though.

//On EDITOR:
 ///repeater is hidden by default - no reason to show it before it gets populated.
 ///get rid of the dataset. Query the collection itself

//In DATABASE -> Assumption: all the keywords in the database are in lower-case (otherwise additional code is needed) <<<< IMPORTANT
import wixData from 'wix-data';
$w.onReady(function () {
 let allItems, items, inputString;
    wixData.query("CollectionName") //use your Collection name (not a dataset)
        .limit(1000)
        .find()
        .then((result) => {
            allItems = result.items;
            $w("#repeater1").data = allItems;
            items = allItems.map(e => { e.keywords = " " + e.keywords + " "; return e }); //add spaces before and after each keywords string (word boundaries)
            $w("#repeater1").show(); //now the user can see all the items and can start searching
        })
        .catch((err) => {
 let errMsg = err.message;
 let errCode = err.code;
        });

    $w("#input1").onKeyPress((event) => {
 let debounceTimer;
 if (debounceTimer) {
            clearTimeout(debounceTimer);
            debounceTimer = undefined;
        }
        debounceTimer = setTimeout(() => {
            inputString = $w("#input1").value; //input processing
 if (typeof inputString === "undefined" || inputString.length === 0 || inputString.trim() === "") {
                $w("#repeater1").data = allItems; //if the search term is empty or contains white-spaes only
            } else {
 let processedString = inputString.replace(/ +(?= )/g, '').toLowerCase(); //get rid of double spaces. Convert to lower case.
 let searchTermWords = processedString.split(" ");
 if (searchTermWords[0] === " ") { searchTermWords.shift(); } //unwanted spaces
 if (searchTermWords[searchTermWords - 1] === " ") { searchTermWords.pop(); } //unwanted spaces
 if (inputString.substring(inputString.length - 1) === " ") { searchTermWords[searchTermWords.length - 1] = searchTermWords[searchTermWords.length - 1] + " "; }
                searchTermWords = searchTermWords.map(e => { if (searchTermWords.indexOf(e) !== searchTermWords.length - 1) { e = " " + e + " " } else { e = " " + e; } return e }); //add spaces between words.
                runSearch(searchTermWords);
            }
        }, 100);

 function runSearch(searchTermWords) {
            items.forEach((e) => {//assign match score
                e.matchScore = 0;
 for (let i = 0; i < searchTermWords.length; i++) {
 if (e.keywords.includes(searchTermWords[i])) { e.matchScore += 1; }
                }
            })
            items.sort(function (a, b) { return b.matchScore - a.matchScore; }); //order by match score. descending.
            $w("#repeater1").data = items; //re-assign repeater to data (based on the new sort).
        }
    })
    $w("#repeater1").onItemReady(($item, itemData, index) => { //Populate repeater; Connect repeater elemnts:
        $item("#image1").src = itemData.image;
        $item("#text2").text = itemData.title;
 //connect all the other elements
    })
});