Hayk Shakhbazyan
Hayk Shakhbazyan

Reputation: 242

Javascript - Highlight specific text inside a string using onClick function

So let's say that we have a HTML paragraph with some text:

<p>Hello. This is a random paragraph with some not so random text inside of this paragraph</p>

And we have an array of strings:

const highlightThisWords = ['random', 'paragraph', 'inside']

What I need is function that will highlight (change the style) of the text inside of the paragraph that is included inside of the array. Note the word paragraph is twice inside of the tag but i would need to highlight only the specific one that i clicked on. Also I need to do some computation after the click like increment a counter.

Enviroment: React.js without jquery possible

Upvotes: 1

Views: 1942

Answers (3)

Freeman Lambda
Freeman Lambda

Reputation: 3655

const highlightThisWords = ['random', 'paragraph', 'inside'];
const pNode = document.querySelector('p');

// turn pNode into a highlight-aware DOM
pNode.innerHTML = pNode.textContent.split(' ').map(word => {
  return highlightThisWords.includes(word) ? `<span>${word}</span>` : word;
}).join(' ');

const potentialHighlights = pNode.querySelectorAll('span');
potentialHighlights.forEach(highlightableWord => {
  highlightableWord.addEventListener('click', function(e) {
    // dehighlight all the rest
    pNode.querySelectorAll('.highlighted').forEach(highlighted => {
      highlighted.classList.remove('highlighted')
    });
    // highlight the clicked word
    highlightableWord.classList.add('highlighted');
  });
});
.highlighted {
  color: red;
}
<p>Hello. This is a random paragraph with some not so random text inside of this paragraph</p>

Above you find a sample snippet in vanilla js, implementing a minimal solution to your question. There is no human-sane way of determining which exact word was clicked in the paragraph, unless you wrap that word in an html tag of its own. The proposed answers so far are wrapping every single word into a tag. While this works, it would not perform great if you have long paragraphs (imagine thousands of DOM nodes in your memory just for a paragraph element). What I propose is to wrap only "potentially highlightable" words in tags.

Upvotes: 1

user1267177
user1267177

Reputation:

You can either create a custom component and use that custom component for split words with " ", I did however tried to create a jsfiddle which isn't very clean, but shows a demo on how it'd work. To show the code on this post:

class Hello extends React.Component {
  constructor() {
    super();
    this.handleClick = this.handleClick.bind(this);
  }
  split(str) {
    return str.split(" ");
  }
  make(str, i) {
    return <span key={i} style={{marginLeft:3}} onClick={this.handleClick}>{str}</span>;
  }
  handleClick(e) {
    console.log(this.props.highlights, e.target.innerText);
    if (this.props.highlights.indexOf(e.target.innerText) !== -1) {
      e.target.style.background = "red";
    }
  }
  render() {
    const parts = this.split(this.props.name);
    return <div>{parts.map((d, i) => {
        return this.make(d, i);
    })}</div>;
  }
}

ReactDOM.render(
  <Hello highlights={['random', 'paragraph', 'inside']} name="This is a random paragraph with some not so random text inside of this paragraph" />,
  document.getElementById('container')
);

Upvotes: 1

Dane
Dane

Reputation: 9552

Since you are using React, you can use String.prototype.split() to split the whole text into array of individual words, and then use conditional rendering to render them as highlighted or not:

class MyComponent extends React.Component {
  render() {
    const arrayOfStrings = stringContainingParagraph.split(' ');

    return (
      <div>
        {arrayOfStrings.map((elem) => (
          ( highlightThisWords.indexOf(elem) !== -1 ) ?
          <mark>{elem}</mark> :
          <span>{elem}</span>
        ))}
      </div>
    );
  }
}

You can then customize this code as you wish ( increment a counter, or using onClicks to get your desired functionality ).

Upvotes: 0

Related Questions