0

I have address options and Autocomplete field which users can filter and find their address. For example these are the addresses

[
    {
        "id": "af332e9d205ca",
        "label": "500 S Himes Ave Apt 2 Tampa, FL 33609",
        "data": {
            "zip": "33609",
            "city": "Tampa",
            "state": "FL",
            "streetAddress": "500 S Himes Ave",
            "secondaryAddress": "Apt 2"
        }
    },
    {
        "id": "53ffcb3f03da6",
        "label": "500 S Himes Ave Apt 20 Tampa, FL 33609",
        "data": {
            "zip": "33609",
            "city": "Tampa",
            "state": "FL",
            "streetAddress": "500 S Himes Ave",
            "secondaryAddress": "Apt 20"
        }
    },
    {
        "id": "072cd5f7c09c4",
        "label": "500 S Himes Ave Apt 21 Tampa, FL 33609",
        "data": {
            "zip": "33609",
            "city": "Tampa",
            "state": "FL",
            "streetAddress": "500 S Himes Ave",
            "secondaryAddress": "Apt 21"
        }
    },
    {
        "id": "c0fce5285fa31",
        "label": "500 S Himes Ave Apt 22 Tampa, FL 33609",
        "data": {
            "zip": "33609",
            "city": "Tampa",
            "state": "FL",
            "streetAddress": "500 S Himes Ave",
            "secondaryAddress": "Apt 22"
        }
    },
    {
        "id": "306f91ef7f85d",
        "label": "500 S Himes Ave Apt 23 Tampa, FL 33609",
        "data": {
            "zip": "33609",
            "city": "Tampa",
            "state": "FL",
            "streetAddress": "500 S Himes Ave",
            "secondaryAddress": "Apt 23"
        }
    },
]

This is the filtering function

const filterOptions = useCallback((options: IOption[], state) => {
    const newOptions: IOption[] = [];

    options.forEach((element) => {
      if (element.label.toLowerCase().includes(state.inputValue.toLowerCase())) {
        newOptions.push(element);
      }
    });
    return newOptions;
  }, []);

I am filtering against the label of each address object. Let's take this one 500 S Himes Ave Apt 2 Tampa, FL 33609.

500 S Himes Ave Apt 2 - works fine 500 S Himes Ave 2 - Doesn't work as String.prototype.includes just checks the substring with an order from the position ( 0 if not mentioned ) and in this case it will return false.

What is the better alternative for these cases where the user can input the text in arbitrary order?

Norayr Ghukasyan
  • 1,298
  • 1
  • 14
  • 28
  • What do you mean by "arbitrary order"? Is `Apt S Himes 500` also valid? – SSM Jun 20 '22 at 17:42
  • I shouldn't restrict the user to input in the same order as the labels are. `500 S Himes Ave 2` is missing `Apt` before the `2` that's why `includes` returns false, but the user shouldn't care about it. – Norayr Ghukasyan Jun 20 '22 at 17:45
  • Like you said, `String.includes` checks for substring. If you want to search by keywords instead, split the search string into individual words and check if each object includes any of them. – bryce Jun 20 '22 at 17:47
  • I got that, I'm asking is `Apt S Himes 500` valid? Do you just need to check if all the words in the user input match or you need them to still be increasing order? Not necessarily consecutive but still increasing or the order doesn't matter at all? – SSM Jun 20 '22 at 17:48
  • [Javascript fuzzy search that makes sense](https://stackoverflow.com/questions/23305000/javascript-fuzzy-search-that-makes-sense) might be of use to you. – Andrew Morton Jun 20 '22 at 17:49
  • The order can be different yes, for sure most of the users will write in a proper order, but I should cover also those cases. – Norayr Ghukasyan Jun 20 '22 at 17:49
  • As already mentioned it looks like fuzzy search is probably what you're looking for. For a library see [fusejs](https://fusejs.io/) – pilchard Jun 20 '22 at 17:53
  • Thanks for mentioning the fuzzy search. I haven't heard about it before. Checking the link you provided. Seems like there are a few good options. – Norayr Ghukasyan Jun 20 '22 at 17:55
  • @NorayrGhukasyan Are the labels surely separated by single spaces? – SSM Jun 20 '22 at 17:57
  • @SSM Yes, as I know.I am getting them from Smarty US Addresses Autocomplete Pro service. – Norayr Ghukasyan Jun 20 '22 at 18:19

1 Answers1

0

You can filter the objects whose label contains all the labels that are present in the user's input.

const data = [
  { id: "1", label: "500 S Himes Ave Apt 2 Tampa, FL 33609" },
  { id: "2", label: "500 S Himes Ave Apt 20 Tampa, FL 33609" },
  { id: "3", label: "500 S Himes Ave Apt 21 Tampa, FL 33609" },
  { id: "4", label: "500 S Himes Ave Apt 22 Tampa, FL 33609" },
  { id: "5", label: "500 S Himes Ave Apt 23 Tampa, FL 33609" },
];

const userInput = "500 S Himes Ave 2";
const result = data.filter(({ label }) =>
  userInput.split(" ").every((l) => label.split(" ").includes(l))
);

console.log(result);
SSM
  • 2,855
  • 1
  • 3
  • 10