React: Insert value at cursor - javascript

I need to add a value (from the dropdown), this will be added in the input field 'at the position of the cursor':
import { useState } from "react";
import "./styles.css";
export default function App() {
const [cur, setCur] = useState("");
const [state, setState] = useState("");
const [dropVal, setDropVal] = useState("");
const handleChange = (e) => {
setState(e.target.value);
// gives cursor index
// this only shows cursor position if user types
// I need to track the position of the cursor and add dropVal there
setCur(e.target.selectionStart);
};
return (
<div className="App">
<input onChange={(e) => handleChange(e)} value={state} />
<select onChange={(e) => setDropVal(e.target.value)} >
<option>ONE</option>
<option>TWO</option>
</select>
</div>
);
}
I tried this, which is incomplete, couldn't find a way to implement it anywhere.
Would appreciate the help, thanks in advance!!

What you are looking for is the selectionStart and selectionEnd properties on an input field.
Basically, you can attach an onBlur listener on your input field and inside it you can access the selectionStart property and save it in state.
Blur means that the input field has lost its focus (meaning you have clicked somewhere outside - like on the dropdown in our case). So once the onBlur is triggered, the selectionStart refers to where your cursor was while the input was still in focus.
Later you can use this value to break the string and add whatever you want (option value in this case) at the position of the cursor.
const onBlur = (e) => {
setCur(e.target.selectionStart);
};
Have a look at this code sandbox

Related

react-jsonschema-form input box out of focus when ObjectFieldTemplate is used

I have rjsf version ^5.0.0-beta.10 installed in package.json and am able to render a proper Form using react-jsonschema-form. The problem is that I'm using ObjectFieldTemplate and every time I enter a character in one of the string input boxes, the box goes out of focus and I have to click on the box again to be able to type anything.
I have read https://github.com/rjsf-team/react-jsonschema-form/issues/2106, which suggested me to move the ObjectFieldTemplate outside of the custom Form definition. I did that and it does not work. I have also read Custom widget with input loses focus in react-jsonschema-form when formData is passed as a prop to the form, which is an advice about setting state, but I'm using functional components rather than class components, so I'm not sure if it's applicable.
The code looks like:
import validator from "#rjsf/validator-ajv6";
import Form from "#rjsf/mui";
const ObjectFieldTemplate = (props) => {
// some logic to be computed
return (
<div>
<h3>{props.title}</h3>
<p>{props.description}</p>
{props.properties.map(function (field) {
// logic to determine the style
return (<fieldset style={style} key={uuidv4()}>{field.content}</fieldset>);
})}
</div>
);
}
const JsonSchemaForm = (props) => {
// define schema and uiSchema
const onSubmit = ({formData}, e) => {
// some logic
}
const onError = (errors) => {console.log(errors);}
return (<Form
schema={schema}
validator={validator}
formData={data}
uiSchema={uiSchema}
onSubmit={onSubmit}
onError={onError}
templates={{ ObjectFieldTemplate }}
/>);
}
Solved. I'm not sure why, but it appears that setting key={uuidv4()} is an expensive computation step that forces the input box to be out of focus.

How to change a class based on focus and change in an input form in React

I have a situation where I want to append a class called shrink to the label text below (Display Name) when I click or type in the input box.
My code is below:
const FormInput = ({ label, ...otherProps} ) => {
let labelClassName = 'formInput-label';
const addLabelClassName = () => {
labelClassName = `${labelClassName} shrink`;
console.log(labelClassName, 'labelClassName inside')
}
console.log(labelClassName, 'labelClassName outside')
return (
<div className="group">
{label &&
<label
className={labelClassName}
>{label}</label>
}
<input onFocus={addLabelClassName } onChange={addLabelClassName } className="formInput" {...otherProps} />
</div>
)
};
My question:
Why does when I focus/ type, at first, React outputs the correct classnames for labelClassName inside as formInput-label shrink, but immediately changes it back to formInput-label at the labelClassName outside position? How would I fix this?
I have also tried to change the code to using the UseState approach like below:
const FormInput = ({ label, ...otherProps} ) => {
const [interaction, setInteraction] = useState('');
let labelClassName = 'formInput-label';
const onInteracting = () => {
setInteraction('interacting')
}
if(interaction === 'interacting') {
labelClassName = `${labelClassName} shrink`;
}
return (
<div className="group">
{label &&
<label
className={labelClassName}
>{label}</label>
}
<input onFocus={onInteracting} onChange={onInteracting} className="formInput" {...otherProps} />
</div>
)
};
And this will append the correct class shrink to labelClassName but I'm not able to take that off when I click outside of the input/form. How may I fix this?
Thank you a ton!
The second approach is a better way because with changing state you will trigger component rerendering (the first approach will never re-render component).
In the second approach, you can take advantage of onBlur event and create a handler which will set the state to the default value. Something like this. You don't need onChange to setIntercation
...
const handleBlur = () => {
setInteraction("");
};
...
and then in input, you have to set up onBlur prop. onChange should not do the same thing as onFocus already does.
....
<input
onFocus={onInteracting}
onBlur={handleBlur}
className="formInput"
{...otherProps}
/>
....

How do I update the default useSate value from a html input?

This Is a simple question. I have a React useState hook,
const [seconds, setSeconds] = useState(0);
how would I be able to update the useState default of 0 to any number I enter, from some kind of a text box or Input in HTML?
Thanks in advance.
You need to add a change event in the input then add the function to handle the input change. like this example.
export default function App() {
const [seconds, setSecond]= useState(0);
const handleSeondChange = (event)=>{
setSecond(event.currentTarget.value);
}
return (
<div className="App">
<input name ="seconds" value={seconds} onChange={handleSecondChange}/>
</div>
);
}
Within an input tag include an onChange handler. For example, <input onChange={(event) => setSeconds(event.target.value)} value={seconds}/>. You're dealing with a controlled input here, so make sure you include the value tag within the input like I included above.

Material UI TextField input type="date" doesn´t get event.target.value

I´m using material ui and react grid from dev extreme to create a table with a input of type date, but when I try to type the date it doesn't recognize the value change until I get to the year value, which cleans the other values. Any Idea of what could be happening?
My Code:
const DateEditor = ({ value, onValueChange }) => {
return (
<TextField
value={value}
type="date"
onChange={event => {
onValueChange(event.target.value)
console.log(event.target.value)
}}
/>
);
};
const DateTypeProvider = React.memo(props => (
<DataTypeProvider
formatterComponent={DateFormatter}
editorComponent={DateEditor}
{...props}
/>
));
Nothing showing.
Showing when getting to year.
Deleting everything when I type next value.
Obs: It works perfectly when I select by the calendar.
just remove value props from the TextField
You should use event.originalTarget Instead of event.target Because originalTarget refers to the element the event is attached to.
target Can change for example for a click event: target Is the inner element that was clicked but not the base element

Select specific text in the editorState

I'm creating a rich text editor using draftjs. Here is the minimal codesandbox so you have an idea of what the issue is.
So I have an helper function getCurrentTextSelection that return me the text that I'm selecting:
const getCurrentTextSelection = (editorState: EditorState): string => {
const selectionState = editorState.getSelection();
const anchorKey = selectionState.getAnchorKey();
const currentContent = editorState.getCurrentContent();
const currentContentBlock = currentContent.getBlockForKey(anchorKey);
const start = selectionState.getStartOffset();
const end = selectionState.getEndOffset();
const selectedText = currentContentBlock.getText().slice(start, end);
return selectedText;
};
When I click outside the TextEditor, the focus is lost so the text isn't selected (but stay the selected one for the editorState).
Is there a programmatic way to reselect this text using the editorState? So that when you click the Select text again button, the text in the TextEditor is selected.
I believe what you're looking to do is restore focus to the editor. If all you do is click outside the editor, the selection state doesn't change (which is why your selected text remains the same). If you then restore focus the same selection becomes visible again, without any changes to editorState.
Draft.js has some documentation about how to do this: https://draftjs.org/docs/advanced-topics-managing-focus/
The Editor component itself has a focus() method which, as you might expect, restores focus to the editor. You can gain access to the component instance with a ref:
const editorRef = React.useRef<Editor>(null)
const selectAgain = () => {
editorRef.current.focus()
};
Then connect the ref to the component and add the click handler to the button:
<div>
<Editor
editorState={editorState}
onChange={onEditorStateChange}
placeholder={placeholder}
ref={editorRef} // added ref
/>
<h2>Selected text:</h2>
<p>{getCurrentTextSelection(editorState)}</p>
// added click handler
<button onClick={selectAgain}>Select text again</button>
</div>
Complete example: https://codesandbox.io/s/flamboyant-hill-l31bn
Maybe you can store the selectedText into EditorState
Using
EditorState.push( editorState, contentState, changeType)
More Info

Categories

Resources