Reputation: 242
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
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
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
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 onClick
s to get your desired functionality ).
Upvotes: 0