1

I am trying to make one custom autocomplete , I am able to do that but I am not able to highlight the matching text

here is my code https://codesandbox.io/s/affectionate-colden-7embr?file=/src/index.js

see when I type john john is highlight in blue color enter image description here

matchItems = (items, regexp) => {
    let match = false;
    items.forEach(item => {
      if (item.search(regexp) > -1) {
        match = true;
      }
    });
    return match;
  };

  filterUsers = (users, regexp) => {
    const filteredUsers = users.filter(
      user =>
        user.name.search(regexp) > -1 ||
        user.id.search(regexp) > -1 ||
        this.matchItems(user.items, regexp) ||
        user.address.search(regexp) > -1 ||
        user.pincode.search(regexp) > -1
    );
    return filteredUsers;
  };

  filterByKeyword = e => {
    const keyword = e.target.value;
    this.setState({ currentInput: keyword });
    if (keyword) {
      const regexp = new RegExp(`${keyword}`, 'i');
      this.setState({ users: this.filterUsers(users, regexp) });
    } else {
      this.setState({ users });
    }
  };

so my code filter works correctly but I am not able to hightlist the text

so my current code works like this without highlight enter image description here

user944513
  • 12,247
  • 49
  • 168
  • 318
  • Does this answer your question? [How to highlight matches within a string with JSX?](https://stackoverflow.com/questions/57597563/how-to-highlight-matches-within-a-string-with-jsx) – Emile Bergeron Jul 08 '20 at 01:24

2 Answers2

1

You should pass currentInput to Name.js as a prop to fill matched words. Try this:

import React from "react";
import PropTypes from "prop-types";

const Name = ({ name, highlight }) => {
  if (!highlight.trim()) {
    return <span>{name}</span>;
  }
  const escapeRegExp = (str = "") =>
    str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
  const regex = new RegExp(`(${escapeRegExp(highlight)})`, "gi");
  const parts = name.split(regex);
  console.log(parts.filter(part => part));
  return (
    <span>
      {parts
        .filter(part => part)
        .map((part, i) =>
          regex.test(part) ? (
            <mark key={i}>{part}</mark>
          ) : (
            <span key={i}>{part}</span>
          )
        )}
    </span>
  );
};

Edit Select with checkboxes and sub headers

Michael
  • 1,806
  • 2
  • 11
  • 20
0

I make this, and works:

const User = React.forwardRef((props, ref) => {
  const { id, name, items, address, pincode } = props.data;
  const { input } = props;

  const formatLabel = label => {
    if (!input) {
      return label;
    }
    return (
      <span>
        {label.split(input).reduce((prev, current, i) => {
          if (!i) {
            return [current];
          }
          return prev.concat(<b key={input + current}>{input}</b>, current);
        }, [])}
      </span>
    );
  };

  let classes = "user";
  if (props.focused) {
    classes += " focused";
  }
  const handleMouseEvent = () => {
    props.handleMouseEvent(props.divId);
  };
  return (
    <div
      tabIndex="0"
      id={props.divId}
      ref={ref}
      className={classes}
      onKeyDown={props.handleKeyPress}
      onMouseMove={handleMouseEvent}
    >
      <Id id={formatLabel(id)} />
      <Name name={formatLabel(name)} />
      <Items items={items.map(item => formatLabel(item))} />
      <Address address={formatLabel(address)} pincode={formatLabel(pincode)} />
    </div>
  );
});

You need to pass down the currenInput value until User Component.

The problem in this solution is that it is case sensitive :(

You could try with other approach like this:

const { input } = props;
  const regexp = new RegExp(`${input}`, 'i');
  
  const formatLabel = label => {
    const formatedLabel = label.replace(regexp, '<b>$&</b>');
    return `<p>${formatedLabel}</p>`
  };

And inside Id Component (and the others) use this render method:

const Id = props => {
  return <div dangerouslySetInnerHTML={{__html: props.id}} />;
};
Nacho Zullo
  • 551
  • 3
  • 5