Reset cursor to the start on <textarea> React - reactjs

i have a textarea in react that i want to create and i want the cursor the start at the beginning when it loses focus. How do i solve this issue?
codesandbox: https://codesandbox.io/s/affectionate-tu-2cd6j6?file=/src/App.js
``
export default function App() {
const textareaRef = useRef();
return (
<div>
<textarea
ref={textareaRef}
id="my-text-area"
defaultValue={"Hello World!"}
rows="2"
tabIndex="-1"
style={{ resize: "none", overflow: "hidden" }}
onBlur={() => textareaRef.current.setSelectionRange(0, 0)}
></textarea>
</div>
);
}
tried using onblur function with setSelectionRange but its not working for some reason.

Played a bit with your code, seems like you are missing focus() call after changing the selection range.
onBlur={() => {
textareaRef.current.setSelectionRange(0, 0);
textareaRef.current.focus();
}}
Then, the cursor will appear at the beginning of the textarea content.
https://codesandbox.io/s/suspicious-tdd-r8t77j?file=/src/App.js

Related

How to change style of input tag based on checkbox?

I have input form and input tag as a button.
Before I was able to make a button which changed styling according to clicking on it but now i try to make this input gray until user check the checkbox. I tried to use <Show> and when property but i cant use when on <Show> tag. Then I tried to use onChange property and it seem to not give me any errors. I just don't understand how can I change styling inside class=" and then connect it to checkbox function? My checkbox is made by using createSignal
Any ideas?
<input
onChange={functionForStyling}
name="submit"
type={"submit"}
value={"Sign up"}
class=""
/>
Assigning a class to a checkbox element is not different than assigning it to any html element.
Here is how you can assign a class to an html element conditionally.
import { createSignal, JSX } from 'solid-js';
import { render } from 'solid-js/web';
const App = () => {
const [isChecked, setIsChecked] = createSignal(true);
const toggle = () => setIsChecked(c => !c);
const handleChange: JSX.EventHandler<HTMLInputElement, Event> = (event) => {
setIsChecked(event.currentTarget.checked);
};
return (
<div>
<style>{`
input.checked {
transform: rotate(45deg);
}
input.unchecked {
transform: rotate(45deg);
}
`}</style>
<input
type='checkbox'
class={isChecked() ? 'checked' : 'unchecked'}
checked={isChecked()}
onChange={handleChange}
/>
{` `}
<button onclick={toggle}>Toggle</button>
</div>
);
};
render(() => <App />, document.body);
https://playground.solidjs.com/anonymous/163ffec6-1293-4702-9ef6-0425461328c3
Please keep in mind that styling a checkbox is not that straightforward. You need to use pseudo selectors etc.

In react, how to detect when the thumb of the range slider is clicked?

<input
ref={left_slider}
onClick={() => set_neg_clicked(!neg_clicked)}
step={100}
type="range"
min={-1000}
max={neg_side_max}
value={neg_side_val}
onChange={(e) => set_neg_side_val(Math.min(900, e.target.value))}
className="slider left"
id="my_neg_range"
style={{
margin: 0,
width: `${neg_side_width}px`,
position: "absolute",
left: 0,
zIndex: 2,
}}
></input>
I need to know when the thumb is clicked. So how can the thumb be accessed in React?
It's an interesting question and the straight answer to that is it's not directly accessible. You have a few options though.
Use a completely different slider other than the input slider.
Add 2 events onClick and OnInput on the input.
When you click anywhere in the slider except the thump, your onInput is going to run. onInput is going to run first then the onClick in case the value is changing. When you just click the thump, onInput won't run, only onClick will get triggered.
The limitation is when you click and not leave the mouse, that's not a complete click.
Here is my crazy idea as code,
import React, { useState, useRef } from 'react';
export default function App() {
const [value, setValue] = useState(1);
let clickRef = useRef(false);
return (
<input
type="range"
min="1"
max="100"
value={value}
onInput={e => {
setValue(+e.target.value);
clickRef.current = true;
}}
onClick={e => {
if (!clickRef.current) console.log('Clicked thump');
clickRef.current = false;
}}
/>
);
}
I used useRef to hold a value, not as an element ref. Changing the value of ref won't trigger a re-render.

How to add TextArea while clicking on image using React JS?

###This is how the code looks like ###
const message = () => {
console.log("Hello World!")
}
return(
<label htmlFor="myInput" ><ShoppingBagIcon style={{width:'26px'}} type="shoppingbag" /></label>
<input id="myInput" type="text" style={{display:'none'}} onClick={message} />)}
export default message
You could use a hook const [shown, setShown] = useState(false)
and render the TextArea based on the value of the hook.
An oversimplified example:
const [shown, setShown] = useState(false)
return (
<>
<button on:click={() => setShown(!shown)}/>
{shown ? <TextArea/> : <WithoutTextArea/>}
</>
);
You can use an extra state say, toggleView in your project. And when a user clicks the image you can set the value true or false. Based on that you can show the textField or not. What I meant is
import React,{useState} from 'react'
const message = () => {
const [showText,toggleShowText] = useState(false);
console.log("Hello World!")
const toggleTextField = () => toggleShowText(!showText)
return(
<div>
<label htmlFor="myInput" ><ShoppingBagIcon style={{width:'26px'}} type="shoppingbag" onClick ={()=>toggleShowText(!showText)}/></label>
{
showText ? (
<input id="myInput" type="text" onClick={message} />
) : (<div/>)
}
</div>
);
}
export default message;
Also in your code, the curly braces are not formatted, I did that Above example.
Also, you can use the ternary operator inside the HTML tag.
<input id="myInput" type="text" style={showText ? {display:'none'}: {display:'inline'}} onClick={message} />
or
style={{display: showText ? 'block' : 'none'}}
I Think the best way of doing hiding or showing an HTML element is using ref
import useRef from react
import { useRef } from "react";
Create a ref
const inputRef = useRef();
Use it in the input or textarea
<input
ref={inputRef}
id="myInput"
type="text"
style={{ display: "none" }}
/>
Now you can change it's any style like this
inputRef.current.style.display = "block";
Why ref?
Because it do not re-render the component. If you use state it will cost a render but using ref it won't
here is the solve
Updated
If you want to hide any elements you can do that like this bellow
ref_variable.current.style.display = 'none'
So when and which element you want to hide just make the display none using the ref.
For example if you want to hide the textarea after input. Just do that.

How to store changes in state using contenteditable element?

How to store changes in state using contenteditable element?
This code store it nicely, but the cursor changes to the beginning of the element.
Do I have to code the cursor position or is there an easy solution?
And no I wont use a form element.
import React, { useState } from 'react';
const About = () => {
const [text, setText] = useState('Hallo');
return (
<div className="about">
<h2>About</h2>
<div className="title column m-0"
contentEditable={true}
suppressContentEditableWarning={true}
onInput={(e) => { setText(e.target.innerHTML) }}
onBlur={(e) => { setText(e.target.innerHTML) }}
dangerouslySetInnerHTML={{ __html: text }}
></div>
</div >
)
}
export default About;
If you only want to store changes and not to have a controlled component you can use onInput prop. It will store the changed text into your state.
<div
contentEditable={true}
suppressContentEditableWarning={true}
onInput={e => setText(e.currentTarget.textContent)}
></div>
P.S: The reason that cursor loses focus is that when you dangerouslySetInnerHTML, you basically are re-mounting every data that you have in your div including the cursor position. That's one of the reasons which makes setting HTML in this way, not recommended.

React DatePicker how to open datepicker on click of icon

Trying to open datepicker on click of icon of react-datepicker component, I have gone through their docs and issues links but found that its not much useful.
<DatePicker
{...startDateOpts}
id='abc'
maxDate={moment()}
onChange={this.handleStartChange}
placeholderText='Start Date'
popoverAttachment={smallScreen ? 'bottom center' : undefined}
popoverTargetAttachment={smallScreen ? 'top center' : undefined}
popoverTargetOffset={smallScreen ? '0px 0px' : undefined}
/>
I tried from React-datepicker docs link but no luck.
Just wrap DatePicker with label. All click inside label call focus on input, that open calendar.
<label>
<DatePicker/>
</label>
If you want to programmatically open the datepicker or if you just don't want to use a <label> wrapper you can set a ref to the datepicker component and use setOpen(bool) to open it. Notice that since we're using refs, the component should be stateful.
Example:
openDatepicker = () => this._calendar.setOpen(true);
render() {
<Datepicker
{...datepickerProps}
ref={(c) => this._calendar = c} />
<img src={iconImg} onClick={this.openDatepicker} />
}
There is currently an open issue on the datepicker's Github stating that this is missing from the docs.
I have just finished that by that way,
svg icon has been imported by webpack
import IconCalendar from 'IconCalendar';
the render function in main component
render() {
const {reportSettings: {
dateTo
}} = this.props;
return (
<div id="date-picker">
<Label for="date-picker-1">Select Results date</Label>
<DatePicker todayButton={"Today"} dateFormat={Constants.DATE_FORMAT} customInput={(<ExampleCustomInput/>)} selected={dateTo} onChange={this.handleChange}/>
</div>
);
}
Secondary component that renders input field and icon
class ExampleCustomInput extends Component {
static propTypes = {
onClick: PropTypes.func,
value: PropTypes.string
}
render() {
const {value, onClick} = this.props;
return (
<div className="form-group">
<input type="text" className="form-control" value={value} onClick={onClick}/>
<IconCalendar className="date-picker-icon" onClick={onClick}></IconCalendar>
</div>
);
}
}
finally css helped me to display icon on input field
.date-picker-icon {
float: right;
margin-right: 6px;
margin-top: -30px;
position: relative;
z-index: 2;
}
After adding newer version of react-datepicker i.e. 0.30.0 i got props autofocus but, again I got problem that only worked for first time then i tried using ref like below
refs='startDate'
in datepicker then in this object i got
this.refs.startDate.deferFocusInput();
So i called it and I got date-picker open on click of icon
This can be achieved using ref as below:
const datepickerRef = useRef(null); // OR React.createRef(); if you are not using hooks
// OPENS UP THE DATEPICKER WHEN THE CALENDAR ICON IS CLICKED FOR THE INPUT FIELD
function handleClickDatepickerIcon() {
const datepickerElement = datepickerRef.current;
// console.log("datepickerElement = ", datepickerElement);
datepickerElement.setFocus(true);
}
<DatePicker
{...startDateOpts}
id="abc"
maxDate={moment()}
onChange={this.handleStartChange}
placeholderText="Start Date"
popoverAttachment={smallScreen ? "bottom center" : undefined}
popoverTargetAttachment={smallScreen ? "top center" : undefined}
popoverTargetOffset={smallScreen ? "0px 0px" : undefined}
ref={datepickerRef} // attach the ref
/>;
{/* CALENDAR ICON */}
<span className="calender-placment" onClick={() => handleClickDatepickerIcon()}>
<i className="fal fa-calendar-alt" />
</span>
Added in version 0.30.0, I think the customInput prop would allow you to do this. That way you could create your own input component and attach the onClick handler to the icon inside it.
#Jayant Patil I have achieved the functionality of opening react-datepicker on click of an icon.
This is how I did it.
I have created a wrapper component around the date picker and passed an id as props to it.
class DateRangePicker extends React.Component {
constructor(props, context) {
super(props, context);
// DatePicker is a controlled component.
// This means that you need to provide an input value
// and an onChange handler that updates this value.
}
render() {
return <DatePicker
id={this.props.id}
selected={this.props.selected}
onChange={this.props.onChange}
onChangeRaw={this.props.onChangeRaw}
onBlur={this.props.onBlur}
peekNextMonth={true}
showMonthDropdown={true}
showYearDropdown={true}
dropdownMode="select"
placeholderText="MM/DD/YYYY"
dateFormat="MM/DD/YYYY"
shouldCloseOnSelect={true}
defaultValue={null}
/>
}
}
export default DateRangePicker;
Then enclose your icon using a label and then pass the id.
<DateRangePicker
ref={'calendar1'}
id={'fromdate'}
dateFormat={gridAttributes.DEFAULT_DATE_FORMAT}
selected={this.state.fromDate}
onChange={this.handleDateChange.bind(this, 'fromDate')}
onChangeRaw={(e) => this.handleRawFromDateChange(e)}
onBlur={this.handleFromBlur.bind(this)}
peekNextMonth={true}
placeholderText={gridAttributes.DEFAULT_DATE_FORMAT}
showMonthDropdown={true}
showYearDropdown={true}
defaultValue={null}
className="calendar1"
/>
<label className="icon iconCalendar calendar" style={{ fontSize: '20px' }} htmlFor='fromdate' />
This works without affecting any functionality unlike when only enclosing the icon with label as said by #tre
<label>
<DatePicker/> </label>
causes the calendar to be in open and can be closed only when we click outside the calendar.
I don't know but none of these solutions worked for me. So made the following one:
openDatepicker = (e) => {
// find date picker input element
const inputElement = e.target.closest('.my-wrapper-class')?.querySelector('input')
return inputElement?.click();
}
The accepted answer is having some issues in that, like ->
When user select the date, the calender is not closing on date select, as the <label> trying to setOpen = true again so even after selecting the date, the claendar still open.
How to overcome this issue? see below the simple answer ->
this.state = {
openCalendar : false,
date : new Date()
}
handleChange = date => this.setState({ setDate : date });
render(){
return(
<label>
<DatePicker
selected={this.state.date}
onFocus={() => this.setState({ openCalendar: true })}
onChange={this.handleDateChange}
open={this.state.openCalendar}
/>
//you can add any icon here and on click that, the date will work as expected.
<svg/> //add any icon you want
</label>
)
}

Resources