How to not clear input field onClick - javascript

I'm working with React JS and I want to make a hidden button for a text box, of type "Row", such that when I click onto that box, a description will appear on the side, the Row has this structure
<div>
<form key={id}>
<button
className="name"
type="submit"
onClick={clickFunc}
>
{data.text}
</button>
</form>
</div>
Where clickFunc makes a call to enterMouseFunc, a function passed in when called in another component file:
const clickFunc = useCallback((e) => {
e.preventDefault();
enterMouseFunc(e, data);
});
In the description box, there is an input field,
// some other details here
<form key={id} onClick={inputClick}>
<input
type="text"
className="inputParam"
name={id}
onChange={handleChange}
/>
<button
type="submit"
style={{ display: "none" }}
></button>
</form>
My inputClick:
const inputClick = (e) => {
e.preventDefault();
};
My handleChange:
const handleChange = (e) => {
e.preventDefault();
setParameters({ name: e.target.name, value: e.target.value });
};
Which works just fine. However, whenever I click on the Row again, or switch between other Rows, all user's inputs get cleared up. The page doesn't refresh since I already suppress this behavior, but the inputs still get deleted. How to stop it from clearing up the inputs all the time?
Edit:
This is how the interface looks like, where the grey boxes are of type Row. When we click on these boxes, the description will appear on the right as shown:

Are you by any chance triggering the onSubmit of the form? You prevent the inputClick but do not prevent the submit. However, im not sure it would be invoked. Why have a hidden submit button at all?

Does setParameters contain all of the fields values? If so you should copy the existing values before reassigning name and value. If not the issue is elsewhere.
A fix would look like this if that is the case:
const handleChange = (e) => {
e.preventDefault();
setParameters({...parameters, name: e.target.name, value: e.target.value});
};

Unless you would like to submit the form, then you don't necessarily need a <form> element?
Also, having a click event handler on that element (instead of say, a button) is not really common, I am not totally surprised that it causes side effects.
What I would do is remove forms that do not submit: just the standalone inputs that trigger setState/setReducer on change events.
Then you should be able to remove hidden buttons, preventDefault calls, etc.
About the cleaning of the values, I suspect your id value in the key prop to change, which would cause a re-mount of the form children.

Related

How to add dynamically created input field values to a use state array?

Continuing troubleshooting from Adding data to array using UseState onChange
Hi, i am trying to make a button, that adds a new input field,
then, when i click another submit button, i want to take the value from all the input fields and add them to an array in a useState.
I did first try to do it like in the linked post, (adding value of the input field onBlur), the issue with this, is that if the user goes back and changes the value in an input field, the old value will still be there. I need to define that the user is done typing when he clicks the submit button.
So now i am thinking i will need to make a function which runs with another submit button, but how will i then get the values of the dynamically created input fields? I understand how to get value from an input using a state with onChange, but it might be 1 inputfield, or it might be 100.
How could i dynamically add a new inputfield, save the value of all the inputfields created, in an state array, when i click the submit button?
relevant Code so far
const [subjectFieldsCounter, setSubjectFieldsCounter] = useState([])
const [subject, setSubject] = useState([]);
function addSubjectField(){
setSubjectFieldsCounter(oldArray => [...oldArray, "randomValueToIncreaseArraySize"])
}
<div>
<h4>Emne:</h4>
<input type="text" placeholder={"Eks. 'Random subject'"} onBlur={(e) => setSubject(oldArray => [...oldArray, e.target.value])}/>
<div><button onClick={addSubjectField}>+</button></div>
{subjectFieldsCounter.map((field) => (
<h2>
<input type="text" placeholder={"Eks. 'Random subject'"} onBlur={(e) => setSubject(oldArray => [...oldArray, e.target.value])}/>
</h2>
))}
</div>

How to trigger an onClick event in react from a parent component to trigger its childs checkbox value?

I have a form with state handled in a context. within the form I have a checkbox component which I am trying to have its state handled within the context. So when I submit the form the checkbox returns a Boolean whether it is checked or not. I'm having trouble with the event handler triggering the checkbox.
I have a number of textfields in the form which are behaving as expected and their values can be seen in the Db once the form is submitted.
Within the checkbox component the actual input is hidden for styling purposes. So the user will be clicking on the label(which is styled to look like a checkbox) or a secondary label (acting as a label)
I'd like it so that when a user clicks on either of the labels the checkbox is triggered. I had the onClick on the checkbox input but seeing as it's display is hidden the user cannot trigger the event.
If I put the onClick on either of the labels or a parent element my onChange functions e.target is pointing to the wrong location.
Is there a way to pass in the the input as the e.target? if the onClick event is on the outer div?
onChange (within RecordForm.js)
const onChange = (e) => {
setRecord({ ...record, [e.target.name]: e.target.value });
};
Checkbox.js
const CheckBox2 = ({ value, label, name, onChange }) => {
return (
<CheckBoxContainer onClick={onChange}>
<LabelContainer>
<CheckboxInput
type='checkbox'
value={value}
name={name}
/>
<CheckBoxLabel>
<Tick className='Tick' />
</CheckBoxLabel>
</LabelContainer>
<VisibleLabel>{label}</VisibleLabel>
</CheckBoxContainer>
);
};
export default CheckBox2;

React/Next.js how to get other Element event target value on button click

I have an input element and a button in React:
<li><input type="text" placeholder="Enter new ID"></input>
<button onClick={(e)=>this.saveKonfigElementHandler()}>Save</button></li>
Now, when I enter some value into the input field, I want to save the value into some array when I click on the button.
Is it somehow possible to get a reference to that input field (e.g. the target.value of the input field) to save it when clicking the button?
Or would I simply have to do it with an onChange event that saves the current input value into some Variable, and when I click the button, I will simply retrieve that value to save it into some array? Maybe that would be a lot simpler.
E.g:
<input type="text" value={this.state.inputFieldText.join('')} onChange={(event) => this.textHandler(event)}></input>
in the textHandler Method, I will save the target value from the input field into a Class Component state variable in the textHandler() method. And when I click the button, I retrieve that state value and can do some manipulation with it?
A modern way to do it, with function components, hooks and a controlled form element, is:
import { useState } from 'react'
function MyComponent({ initialId, onSave }) {
const [newId, setNewId] = useState(initialId)
return (
<li>
<input
type="text"
placeholder="Enter new ID"
onChange={(e) => setNewId(e.target.value)}
/>
<button onClick={() => onSave(newId)}>Save</button>
</li>
)
}
I'd also note that it is considered better accessibility practice to use a label element for describing the purpose of your field, rather than a placeholder. Placeholders are more appropriate for example input.
Is it somehow possible to get a reference to that input field (e.g. the target.value of the input field) to save it when clicking the button?
Yes.
Or would I simply have to do it with an onChange event that saves the current input value into some Variable, and when I click the button, I will simply retrieve that value to save it into some array? Maybe that would be a lot simpler.
That would be a slightly more React way to do it.
Your DOM-only approach is more "uncontrolled" (see these docs for what controlled/uncontrolled means). You'd do it like this:
Change your onClick to pass e to the handler:
onClick={(e)=>this.saveKonfigElementHandler(e)}
In saveKonfigElementHandler, use e.target.previousElementSibling to access the input:
saveKonfigElementHandler(e) {
const { value } = e.target.previousElementSibling;
// Use `value` ...
}
That's fragile, of course; if you change your structure so another element is between the button and the input, or the input is within a container element, etc., it'll break — which is one argument for the controlled approach. You could store a link to the input in a data attribute on the button:
<li><input id="id-input" type="text" placeholder="Enter new ID"/>
<button data-input="#id-input" onClick={(e)=>this.saveKonfigElementHandler(e)}>Save</button></li>
and then use querySelector to get it:
saveKonfigElementHandler(e) {
const { value } = document.querySelector(e.target.getAttribute("data-input"));
// Use `value` ...
}
but the you're having to keep selectors unique, etc.
Which you choose, controlled or uncontrolled, is ultimately up to you.
I'm not sure about your question. Do you want something like this ?
<button data-input="#id-input" onClick={this.saveKonfigElementHandler(value)}>Save</button></li>
saveKonfigElementHandler = (value) => (event) => {}

Input form - change the running order of onChange and isDisabled

I have implemented in React a webpage with 3 input fields, each one with the properties of
onChange={this.handleChange} and disabled={this.isDisabled()}
The desired behavior is that when an input field contains 2 digits, the focus will be moved to the next input field.
As long as the field doesn't contain 2 digits, the fields next to must be disabled.
What actually happens, when I type the second digit in the first field, it runs the handleChange function, that function checks whether the field contains 2 digits, find out that yes, and moves the focus to the next input field.
But the next field is disabled! (because the isDisabled function didn't run yet!)
So the cursor doesn't move..
I want to change the order of the happenings, or any other way to solve it.
Do you have any suggestions?
The problem is that this.isDisabled() runs immediately in render but this.handleChange runs on click and most possibly doesn't change the state thus no rerender.
You sholdn't run function on next input, you should pass true or false to its disabled prop. Just make handleChange update the state which defines which fields are disabled. And pass that state to your inputs accordingly.
I had faced the same issue a few days back. My approach was however using react states and focusing the input by its id, that was fetched from state;
So first we make a input - id map for our convenience. And use document.getElementById(this.state.active).focus() function. We change our state via our change handler.
render() {
this.setInputFocus();
return (
<div className="App">
<input id="1" onChange={this.onChange} />
<input id="2" onChange={this.onChange} />
<input id="3" onChange={this.onChange} />
</div>
);
}
setInputFocus = () => {
if (document.getElementById(this.state.active)) {
document.getElementById(this.state.active).focus();
}
};
onChange = e => {
if (e.target.value.length === 2) {
this.setState({ active: this.state.active + 1 });
}
};
Here is a full code that somewhat solves the issue

input field not behaving as expected while making atom plugin?

I'm newbie in making atom plugins. I have to make a field which will take an input. I'm using etch for component management. In the render method, I've made this input field
<input
name={'component'}
type={'text'}
onchange={this.onInputChange}
value={this.componentName}
/>
I've made this onInputChange method which looks like :
onInputChange = (event) => {
this.componentName = event.target.value;
etch.update(this);
}
but I'm getting an event which comes after some time (kinda debounced event), furthermore I'm not able to delete the text from input. What is the right way to make an input.
<div class="native-key-bindings">
<input/>
</div>
Try wrapping it in this way. It will also fix the delete issue.

Categories