How can you get highlighted text (window.getSelection()) in ReactJS - javascript

I have been learning to make a custom markdown editor. However I just ran into the problem of getting the highlighted text before wrapping it with the markdowns. Here's my example
class TextArea extends React.Component {
constructor(props){
super(props);
this.state = {
comment:'He oppose at thrown desire of no. Announcing impression unaffected day his are unreserved indulgence.She oppose at thrown desire of no..'
};
this.onClickMakeBold = this.onClickMakeBold.bind(this);
}
render(){
return <div>
<button onClick={this.onClickMakeBold}>Bold</button>
<div>
<textarea ref="textarea">{this.state.comment}</textarea>
</div>
</div>
}
onClickMakeBold(){
console.log(getSelectionText())
}
}
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control"){
text = document.selection.createRange().text;
}else{
alert('no')
}
return text;
}
React.render(<TextArea />, document.getElementById('container'));
The result from getSelectionText() function doesn't return any text at all. How can I get the highlighted text in ReactJS?

By clicking on the button, you deselect the text before the event is triggered.
Pass the callback to your button as onMouseDown, as this event happens before the standard click side effects take place.
Also: if you want the text to remain selected after the event has been processed, use event.preventDefault() in your callback function.

here is solution with react hook pure without any library!
to clone and the small package or any question you can check:
https://github.com/Farbod29/React-text-highlighter-with-hook-
import React, { useState, useEffect } from 'react';
import './highlight.css';
export default function Highlighter() {
const [highlightedText, setHighlightedText] = useState(
'highlighted text will be shown here!'
);
useEffect(() => {
const saveSelection = () => {
setHighlightedText(window.getSelection().toString());
};
document.addEventListener('mouseup', saveSelection);
return () => document.removeEventListener('mouseup', saveSelection);
}, []);
return (
<>
<section className="card">
<div>
<div className="margin-top-zero txt">
Here is react text highlighter with hook and use state/Effect,
understand if you have any question just email or add issue in above git ripo!
</div>
{/* {ghasem} */}
<div className="txt">{highlightedText}</div>
<div // parent of button
>
<button className="btn"> Add Highlighted text </button>
</div>
</div>
</section>
</>
);
}

Related

Check if a div element can receive paste event i.e if it is focused

I am capturing a paste event in a div element.
<div onPaste={(e)=>console.log(e.clipboardData.getData("Text"))}}>
</div>
This, however only works if the element has been clicked into (and the user hasn't clicked outside of it)
How do I indicate to the user that the element is able to receive a paste (i.e is focused, I suppose)
document.activeElement remains focused on body I suppose because the div is not an input
You should use react hook useState for that:
import { useState } from 'react'
const App = () => {
const [focused, setFocused] = useState(false)
const onFocus = () => {
setFocused(true)
}
const onBlur = () => {
setFocused(false)
}
return (
<div>
<div onFocus={onFocus} onBlur={onBlur}>{focused ? 'focused' : 'not focused'}</div>
</div>
)
}
export default App
And now if the focused variable is true, the element is focused and if it's false the element is blurred.

Submit button not changing from disabled to enabled after Validation of field length

I have a React form with just a text area and a submit button. I set the submit button's state to disabled to begin with, and then after the user enters 100 chars or more I want to enable the Submit button.
The issue I'm having right now is that after I input more than 100 chars, the submit button remains disabled and doesn't change to enabled state.
This is the updateFieldLength function I am calling upon the textarea field's onChange.
const updateFieldLength = e => (
setText(e.target.value), () => (
validateFieldLength()
)
)
and this is the validateFieldLength function:
function validateFieldLength() {
if (submitDisabled && text.length > 100) {
setSubmitDisabled(false);
} else if (!submitDisabled && text.length <= 100) {
setSubmitDisabled(true);
}
}
Your problem seems to be that the onchange event is triggered only when textarea loses focus. I guess it would work with the oninput event, shown below
const setBackground = (element, background) => {
element.style.background = background;
}
<textarea id="test-on-change" onchange="setBackground(this, 'green')" rows="10" cols="30">Example with onchange, start typing...</textarea>
<textarea id="test-on-input" oninput="setBackground(this, 'yellow')" rows="10" cols="30">Example with oninput, start typing...</textarea>
This should do the job
import React from 'react'
const MyComponent = () => {
const [text, setText] = useState('')
const handleTextChange = e => {
setText(e.target.value)
}
return(
<>
<textarea onChange={handleTextChange}>
{text}
</textarea>
<button disabled={text.length < 100}>
Submit
</button>
</>
)
}

Select a value from dropdown using React

I am making a very simple autocomplete section in a react application.
Code as follows,
index.js
import React from 'react';
import { render } from 'react-dom';
import Autocomplete from './Autocomplete';
const styles = {
fontFamily: 'sans-serif',
textAlign: 'left',
};
const items = ['Moscow', 'Ufa', 'Tver', 'Alma ata'];
function onAutoCompleteHandle(val) {
alert(val);
}
const App = () => (
<div style={styles}>
<Autocomplete items={items} onAutocomplete={onAutoCompleteHandle.bind(this)}/>
</div>
);
render(<App />, document.getElementById('root'));
autocomplete.js
Render method:
const showSuggest = {
display: this.state.show ? 'block' : 'none',
}
return (
<div>
<input type="text"
className="autoCompleteInput"
onChange={this.handleChange}
ref={input => { this.textInput = input; }}
onClick={this.handleClick}
onKeyPress={this.handleKeyPress}
/>
<span className='suggestWrapper' style={showSuggest}>
<ul className='suggestAutocomplete'>
{this.state.items.map((item, i) => {
return
<li key={i} onClick={this.selectSuggestion}>
{item}
</li>
})}
</ul>
</span>
</div>
)
Complete working example: https://codesandbox.io/s/react-autocomplete-nbo3n
Steps to reproduce in the above given sandbox example:
-> Click on the input box.
-> Enter single alphabet eg.., a .
-> This gives the two items as result Ufa, Alma ata .
-> Press the down arrow key in keyboard.
As nothing happens here, unable to select any of the dropdown items.
As of now things work only if we move the mouse over the dropdown and select any item but I am in the need to implement the same behaviour for key down and enter.
Expected behaviour:
-> On keydown/keyup should be able to navigate the dropdown list items.
-> On click enter key on an item then that item should be the selected one.
I have tried assigning ref={input => { this.textInput = input; }} to the ul list items suggestAutocomplete but that also doesn't help..
Really I am stuck with this for very very long time. I humbly request you to consider this question.
It is also okay if you change this existing code, but I need to have both mouse selection and keyboard selection as well in the autocomplete..
Initialize a state with value -1
Add an event on keyDown
something like this:
handleKeyDown(e) {
if (e.keyCode == 40) { //down
this.setState({active: ++this.state.active})
} else if (e.keyCode == 38) { //up
this.setState({active: --this.state.active})
} else if (e.keyCode == 13) { //enter
e.preventDefault();
if (this.state.active > -1) {
this.selectSuggestion();
}
}
};
On click, reset the state to -1 again.
Check this: https://codesandbox.io/s/react-autocomplete-cf2yd

Textarea alike but for only one line

Something I like about the textarea element is that allows automatic spell checker. This is not happening with input text element. I need an element like textarea that will only show one line and never go to a next line even if the user press enter. I tried row='1' but doesn't matter if the user press enter the content moves to a next line. This could also be a react component. Exist something like that?
Like this:
document.querySelector('textarea').addEventListener('keydown', (e) => {
if (e.keyCode === 13) e.preventDefault();
});
textarea {
white-space: nowrap;
overflow:hidden;
}
<textarea rows="1"></textarea>
As your question tagged ReactJS
import React from 'react';
class App extends React.Component {
handleTextArea = (e) =>{
let lineCount = 0;
if (e.keyCode == 13) {
lineCount++;
}
if (lineCount >= 1) { // set here how may lines you want
e.preventDefault();
return false;
}
}
render() {
return (
<div>
<textarea onKeyDown={this.handleTextArea}>only one line</textarea>
</div>
)
}
}
export default App

Create a numbered list within a textarea element in ReactJs

I am trying to create a text area element, where on load it should display a "1. ". The user can then type a sentence and hit return. Upon return it should render a "2." in the next line. When a user is on a line that has no text and clicks backspace, it should delete the number and return the focus to the previous number point. To illustrate this: User is on line "2." -> They press backspace which removes the "2." bullet point. -> returns them to the last character of line "1."
So far i have figured out this much:
const React = require('react');
const TextArea = React.createClass({
getInitialState: function() {
return {
textAreaVal: '1. '
};
},
editTextArea: function(value) {
this.setState({
textAreaVal: value
});
},
render: function() {
return (
<div className={"container"}>
<textarea autoFocus className={"proposal-textarea"} wrap="hard" defaultValue ={this.state.textAreaVal}
onChange={this.editTextArea} />
</div>
);
},
});
module.exports = TextArea;
Does anyone have any thoughts on the best way I can accomplish this?
What you're looking for is Reacts onKeyDown event.
Same way you have onChange set up, set up a function for onKeyDown that sends to this.handleKeyDown(event). Within that function, test event.charCode to determine which key was pressed (enter should be 13 and backspace should be 8), and then apply the necessary actions as needed.
EDIT: Moving my comment to the answer block;
To handle the incrementing number, simply add a secondary state element, lineNumber. Initialize it to 1 at start. Whenever you detect a keypress of Enter, increment lineNumber and append "\n" + this.state.lineNumber + ". " to your textAreaVal.
Well, look at this fiddle
const { Component, PropTypes } = React;
class NumberedTextArea extends Component {
constructor() {
super();
this._onKeyDown = this._onKeyDown.bind(this);
this.state = {
counter: 2,
text: `1. `
}
}
_onKeyDown(e) {
console.log(e.keyCode);
if (e.keyCode ===13) {
console.log(this.refs.text.value);
this.refs.text.value = `${this.refs.text.value}\n${this.state.counter++}. `;
e.preventDefault();
e.stopPropagation();
}
}
render() {
const style = {
height: 300,
width: 200
};
return (
<textarea ref="text" onKeyDown={this._onKeyDown} style={style}>
{this.state.text}
</textarea>
);
}
}
ReactDOM.render(
<NumberedTextArea />,
document.getElementById('root')
);

Categories

Resources