I'm trying to capture the value of whatever is pasted into a text input, but it's not showing up in the text input for some reason
import React from "react";
export default function App() {
handleOnPaste = e => {
e.stopPropagation();
e.preventDefault();
const clipboardData = e.clipboardData || window.clipboardData;
const pastedData = clipboardData.getData("Text");
console.log(pastedData);
};
return (
<div className="App">
<input
type="text"
onPaste={e => this.handleOnPaste(e)}
/>
</div>
);
}
It is working, just declare the function in a proper way like,
const handleOnPaste = e => {
e.stopPropagation();
e.preventDefault();
const clipboardData = e.clipboardData || window.clipboardData;
const pastedData = clipboardData.getData("Text");
console.log(pastedData);
};
I. declare your function with const
const handleOnPaste = e => {
// Implementation
}
II. pass your function without this because this is a function component, not a class component.
return (
<div className="App">
<input
type="text"
onPaste={e => handleOnPaste(e)}
/>
</div>
);
You can also pass your function like:
onPaste={handleOnPaste}
As mentioned in other answers, you are mixing class based component's concepts in functional component. So use const to define handlers and don't use this.
See Working demo.
FYI - You can also use navigator.clipboard
Code snippet
export default function App() {
const handleOnPaste = e => {
e.stopPropagation();
// First way
const clipboardData = e.clipboardData || window.clipboardData;
const pastedData = clipboardData.getData("Text");
console.log(pastedData);
// Another way -- navigator.clipboard
navigator.clipboard.readText().then(copiedText => console.log('copiedText', copiedText));
};
return (
<div className="App">
<input
type="text"
onPaste={handleOnPaste}
/>
</div>
);
}
Your e.preventDefault() is what's stopping the input from updating. It's unnecessary if you're happy for the field to update
Related
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.
I'm using react-dates SingleDatePicker. The visibility of the calendar is controlled by the focused prop. When using tabs on the website, I don't want the calendar to open, I want it to open on enter key. Is there a way to achieve this? Thanks!
You should to control "focused" property and onFocusChange method. Also set the listener to container. For example
.....
const [focusedInput, setFocusedInput] = useState(null);
const handleUserKeyPress = (evt) => {
if (evt.keyCode === 13 && !evt.shiftKey) setFocusedInput(true);
};
....
<div onKeyUp={handleUserKeyPress}>
<SingleDatePicker
focused={focusedInput}
onFocusChange={({ focused }) => {
const focus = focusedInput && focused ? true : false;
setFocusedInput(focus);
}}
.....
/>
</div>
.....
I'm tasked with crawling website built with React. I'm trying to fill in input fields and submitting the form using javascript injects to the page (either selenium or webview in mobile). This works like a charm on every other site + technology but React seems to be a real pain.
so here is a sample code
var email = document.getElementById( 'email' );
email.value = 'example#mail.com';
I the value changes on the DOM input element, but the React does not trigger the change event.
I've been trying plethora of different ways to get the React to update the state.
var event = new Event('change', { bubbles: true });
email.dispatchEvent( event );
no avail
var event = new Event('input', { bubbles: true });
email.dispatchEvent( event );
not working
email.onChange( event );
not working
I cannot believe interacting with React has been made so difficult. I would greatly appreciate any help.
Thank you
This accepted solution appears not to work in React > 15.6 (including React 16) as a result of changes to de-dupe input and change events.
You can see the React discussion here: https://github.com/facebook/react/issues/10135
And the suggested workaround here:
https://github.com/facebook/react/issues/10135#issuecomment-314441175
Reproduced here for convenience:
Instead of
input.value = 'foo';
input.dispatchEvent(new Event('input', {bubbles: true}));
You would use
function setNativeValue(element, value) {
const valueSetter = Object.getOwnPropertyDescriptor(element, 'value').set;
const prototype = Object.getPrototypeOf(element);
const prototypeValueSetter = Object.getOwnPropertyDescriptor(prototype, 'value').set;
if (valueSetter && valueSetter !== prototypeValueSetter) {
prototypeValueSetter.call(element, value);
} else {
valueSetter.call(element, value);
}
}
and then
setNativeValue(input, 'foo');
input.dispatchEvent(new Event('input', { bubbles: true }));
React is listening for the input event of text fields.
You can change the value and manually trigger an input event, and react's onChange handler will trigger:
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {value: ''}
}
handleChange(e) {
this.setState({value: e.target.value})
console.log('State updated to ', e.target.value);
}
render() {
return (
<div>
<input
id='textfield'
value={this.state.value}
onChange={this.handleChange.bind(this)}
/>
<p>{this.state.value}</p>
</div>
)
}
}
ReactDOM.render(
<Form />,
document.getElementById('app')
)
document.getElementById('textfield').value = 'foo'
const event = new Event('input', { bubbles: true })
document.getElementById('textfield').dispatchEvent(event)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'></div>
Here is the cleanest possible solution for inputs, selects, checkboxes, etc. (works not only for react inputs)
/**
* See [Modify React Component's State using jQuery/Plain Javascript from Chrome Extension](https://stackoverflow.com/q/41166005)
* See https://github.com/facebook/react/issues/11488#issuecomment-347775628
* See [How to programmatically fill input elements built with React?](https://stackoverflow.com/q/40894637)
* See https://github.com/facebook/react/issues/10135#issuecomment-401496776
*
* #param {HTMLInputElement | HTMLSelectElement} el
* #param {string} value
*/
function setNativeValue(el, value) {
const previousValue = el.value;
if (el.type === 'checkbox' || el.type === 'radio') {
if ((!!value && !el.checked) || (!!!value && el.checked)) {
el.click();
}
} else el.value = value;
const tracker = el._valueTracker;
if (tracker) {
tracker.setValue(previousValue);
}
// 'change' instead of 'input', see https://github.com/facebook/react/issues/11488#issuecomment-381590324
el.dispatchEvent(new Event('change', { bubbles: true }));
}
Usage:
setNativeValue(document.getElementById('name'), 'Your name');
document.getElementById('radio').click(); // or setNativeValue(document.getElementById('radio'), true)
document.getElementById('checkbox').click(); // or setNativeValue(document.getElementById('checkbox'), true)
I noticed the input element had some property with a name along the lines of __reactEventHandlers$..., which had some functions including an onChange.
This worked for finding that function and triggering it
let getReactEventHandlers = (element) => {
// the name of the attribute changes, so we find it using a match.
// It's something like `element.__reactEventHandlers$...`
let reactEventHandlersName = Object.keys(element)
.filter(key => key.match('reactEventHandler'));
return element[reactEventHandlersName];
}
let triggerReactOnChangeEvent = (element) => {
let ev = new Event('change');
// workaround to set the event target, because `ev.target = element` doesn't work
Object.defineProperty(ev, 'target', {writable: false, value: element});
getReactEventHandlers(element).onChange(ev);
}
input.value = "some value";
triggerReactOnChangeEvent(input);
Without element ids:
export default function SomeComponent() {
const inputRef = useRef();
const [address, setAddress] = useState("");
const onAddressChange = (e) => {
setAddress(e.target.value);
}
const setAddressProgrammatically = (newValue) => {
const event = new Event('change', { bubbles: true });
const input = inputRef.current;
if (input) {
setAddress(newValue);
input.value = newValue;
input.dispatchEvent(event);
}
}
return (
...
<input ref={inputRef} type="text" value={address} onChange={onAddressChange}/>
...
);
}
React 17 works with fibers:
function findReact(dom) {
let key = Object.keys(dom).find(key => key.startsWith("__reactFiber$"));
let internalInstance = dom[key];
if (internalInstance == null) return "internalInstance is null: " + key;
if (internalInstance.return) { // react 16+
return internalInstance._debugOwner
? internalInstance._debugOwner.stateNode
: internalInstance.return.stateNode;
} else { // react <16
return internalInstance._currentElement._owner._instance;
}
}
then:
findReact(domElement).onChangeWrapper("New value");
the domElement in this is the tr with the data-param-name of the field you are trying to change:
var domElement = ?.querySelectorAll('tr[data-param-name="<my field name>"]')
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>
</>
);
}
I have a textarea in React that I want to turn into a "notepad". Which means I want the "tab" key to indent instead of unfocus. I looked at this answer, but I can't get it to work with React. Here is my code:
handleKeyDown(event) {
if (event.keyCode === 9) { // tab was pressed
event.preventDefault();
var val = this.state.scriptString,
start = event.target.selectionStart,
end = event.target.selectionEnd;
this.setState({"scriptString": val.substring(0, start) + '\t' + val.substring(end)});
// This line doesn't work. The caret position is always at the end of the line
this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1;
}
}
onScriptChange(event) {
this.setState({scriptString: event.target.value});
}
render() {
return (
<textarea rows="30" cols="100"
ref="input"
onKeyDown={this.handleKeyDown.bind(this)}
onChange={this.onScriptChange.bind(this)}
value={this.state.scriptString}/>
)
}
When I run this code, even if I press the "tab" key in the middle of the string, my cursor always appears at the end of the string instead. Anyone knows how to correctly set the cursor position?
You have to change the cursor position after the state has been updated(setState() does not immediately mutate this.state)
In order to do that, you have to wrap this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1; in a function and pass it as the second argument to setState (callback).
handleKeyDown(event) {
if (event.keyCode === 9) { // tab was pressed
event.preventDefault();
var val = this.state.scriptString,
start = event.target.selectionStart,
end = event.target.selectionEnd;
this.setState(
{
"scriptString": val.substring(0, start) + '\t' + val.substring(end)
},
() => {
this.refs.input.selectionStart = this.refs.input.selectionEnd = start + 1
});
}
}
jsfiddle
For anyone looking for a quick React Hooks (16.8+) cursor position example:
import React, { useRef } from 'react';
export default () => {
const textareaRef = useRef();
const cursorPosition = 0;
return <textarea
ref={textareaRef}
onBlur={() => textareaRef.current.setSelectionRange(cursorPosition, cursorPosition)}
/>
}
In this example, setSelectionRange is used to set the cursor position to the value of cursorPosition when the input is no longer focused.
For more information about useRef, you can refer to React's official doc's Hook Part.
Here's a solution in a hooks-style architecture. My recommendation is to change the textarea value and selectionStart immediately on tab insertion.
import React, { useRef } from "react"
const CodeTextArea = ({ onChange, value, error }) => {
const textArea = useRef()
return (
<textarea
ref={textArea}
onKeyDown={e => {
if (e.key === "Tab") {
e.preventDefault()
const { selectionStart, selectionEnd } = e.target
const newValue =
value.substring(0, selectionStart) +
" " +
value.substring(selectionEnd)
onChange(newValue)
if (textArea.current) {
textArea.current.value = newValue
textArea.current.selectionStart = textArea.current.selectionEnd =
selectionStart + 2
}
}
}}
onChange={e => onChange(e.target.value)}
value={value}
/>
)
}
In React 15 best option is something like that:
class CursorForm extends Component {
constructor(props) {
super(props);
this.state = {value: ''};
}
handleChange = event => {
// Custom set cursor on zero text position in input text field
event.target.selectionStart = 0
event.target.selectionEnd = 0
this.setState({value: event.target.value})
}
render () {
return (
<form>
<input type="text" value={this.state.value} onChange={this.handleChange} />
</form>
)
}
}
You can get full control of cursor position by event.target.selectionStart and event.target.selectionEnd values without any access to real DOM tree.