React onKeyPress Render Issue - javascript

I'm attempting to make a component which acts as a sort of bullet list. There's an input field held in an unordered list item (acting as the first bullet point, which by default will always be there). The field has an onKeyPress function that checks whether or not the user presses the return (or Enter) key to create a new bullet point. When that happens, the function adds another identical input field to the bulletList array, which is then rendered on the page using the .map() JS function.
The issue I'm having is the following: On the default (first) input field that is always there, the enter functionality works perfectly. The user can press enter, and a new input field is created below it. The problem happens here: On the second (newly-created) input field, the enter functionality partly works. It logs to the console what it needs to log as a test (indicating it's being triggered) but doesn't render a new input field below. What could be the issue here? Thanks!
The original input field:
<input onKeyPress={(e) => handleAdd(e)} autoFocus />
The adder function:
const handleAdd = (e) => {
if (e.key == "Enter") {
setBulletList([...bulletList, (<input onKeyPress={(e) => handleAdd(e)} autoFocus />)]);
console.log("Worked?");
console.log(bulletList);
}
};

You don't have anything that differentiates the first one from the second one so React is getting confused when there's more than one. React will often warn you to make sure each element has it's own unique keys. If they don't have unique keys/identifiers then React won't update the virtual dom. The virtual dom is what React uses to identify changes that were made.
Give each one it's own class and that should work.

You should add the input value, not the input HTML tag, like this:
const handleAdd = (e) => {
if (e.key == "Enter") {
setBulletList([...bulletList, e.target.value]);
console.log("Worked?");
console.log(bulletList);
}
};

Related

How to use setTimeout in react for if statement?

I like to use only placeholder without label for inputs/forms. Therefore i created a onClick -> set type from text to date.
But if someone has a bad memory and dont know what date to fill in, I created a onMouseleave -> set type from date to text, if its empty.
But if someone want to fill his birthday and the mouse leaves accendently, they will give me a text instead of a date.
Therefore I want to use a setTmeout but it doesn't work as planned.
const [type, setType] = useState("text")
const handleDate = () => {
setType("date")
}
const handleText = () =>{
if(values.birthday === ""){
setType("text")}
}
<input
onChange={handleChange}
value={values.birthday}
type={type}
name="birthday"
placeholder="birthday"
onClick={handleDate}
onMouseLeave={setTimeout(handleText, 3000)}/>
by using onMouseLeave={setTimeout(handleText, 3000)}/> the input field is deselected and i can't type anything in.
I want that the if-query will be checked after 3 seconds and am able to type something in
try this:
<input
onChange={handleChange}
value={values.birthday}
type={type}
name="birthday"
placeholder="birthday"
onClick={handleDate}
onMouseLeave={() => setTimeout(handleText, 3000)}/>
the way you're doing currently it is immediately calling the setTimeout on render, you need to put it as a function
This is very weird UX design, I doubt your users will like it. No one expects that moving the mouse out of the input would replace the contents of the input a few seconds later. And did you consider that people may use a touch screen? Or move to the next input with the Tab key?
How about using a more conventional UX, for example title if you don't want labels?

ReactJS - update component (generated from a list) in the same div

It's a basic question but I searched for a guide without success...
I want to have a list of dropdowns and inputs and each dropdown will change the input next to it.
var list = [{ name: "foo1"}, {name: "foo2"}];
return (
{list.map( (name) => {
return (<div>
<dropdown data={someData}
onChange={(ev) => {
if(ev.value == 'clearIt')
<CHANGE THE NEAR INPUT VALUE>
}
}/>
<input value={name.name} />
</div>)
})});
I don't want to use DOM nor ref cause I understood that it's better to avoid it.
Any suggestions?
Or maybe the ref is the only option?
Thanks
So you can achieve this by doing the following steps:
Create a new component and move the dropdown and input to this new component.
Add state to your component by following this example:
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
Add an event listener onChange to the dropdown with an event handler which can update the state you created in the first step. (Remember to bind the handler in the constructor.
Add the new component within the div element of this example you gave and pass the relevant data you need to the new component you created.
This should allow you to update only the input next to the dropdown. Also it allows you to have different data for each dropdown you created.

ReactJS Element focus() not firing

I have a number input field that I'm trying to focus on after receiving input from a bar-code scanner. In reality the scanner is just a pseudo keyboard that I watch for the tab key to get pressed.
In Edge the input receives focus as expected, but in all other browsers tested (Chrome/Firefox) the input doesn't gain focus. Safari has not been testes since I'm on a PC.
// I'm using a lifecycle method to watch for a change to the components props.
// The onInputFocused will unset the value, but I've disabled to this
// to eliminate any possible race cases?!
componentDidUpdate() {
if (this.props.detail.shouldFocus) {
setTimeout(() => {
this.qtyInput.focus();
}, 250);
// this.props.onInputFocused(this.props.detail);
}
}
render(){
return (
...
<input type="number" className="form-control" min="0" name="qty_received" value={detail.ReceiptQuantityReceived}
ref={(input) => { this.qtyInput = input }}
onChange={(e) => { onQtyReceivedChange(e, detail) }}
onBlur={() => { onReceiveShipmentRowBlur(detail) }} />
);
}
I originally was calling focus without a setTimeout, but attempted the timeout based on some suggestions online. I have also attempted to change the input to text, but that didn't have any effect either.
Doing a console.log on this.qtyInput outputs the expected element.
The only other thing I can think of is that the modal that a user scans in to gains it's focus via a similar function, but it has been removed by the time the focus call should be happening.
To add to the weirdness, I've added a console.log to the input's onBlue event and it is getting fired even though you can't type in the field or have any visual indication of focus.
one thing you must try is add this attribute for your INPUT element
(input autoFocus ..)
this attribute may help you

How do I programatically fill input field value with React?

I have a modal with some input fields. I can easily pass the data automatically with the user typing an input, using onChange function in the input field, as
<Input onChange={this.props.store.handleCategoryChange} type="text" />
and .. (Using a mobx store, irellevant though)
#observable categoryValue;
#action handleCategoryChange = (e, data) => {
this.categoryValue = data.value;
e.preventDefault();
};
However, I want to add a function where the user can pre-fill this with information elsewhere in the application. I have the data to pre-fill the input fields with, but I can't figure out how do actually input it programatically, without the user doing it?
I need to invoke the above handleCategoryChange function. But my variable would be equal to data.value .. Which presents a problem! Invoking this function by myself isn't possible, because I won't have the event e nor a value called data.value as I will "just" pass in a variable by itself.
What's the right way to programatically fill an input field automatically in React, using variables elsewhere? I need to invoke the onChange function somehow, but the input values will be different..
Use controlled component for this situation, define a value property of input element like this:
<Input value={variable_name} ....
Whenever you will update that variable, automatically that value will get populated in input element.
Now you can populate some default value by assigning a value to variable_name and user can update that value by onChange function.
As per DOC:
An input form element whose value is controlled by React in this way
is called a "controlled component".
Pass in the value property for input:
<input type="text" value={this.state.value} onChange={(e) => {this.setState({value: e.target.value })}/>
you can use the controlled component and pass the value to it.
<input type="text" value{this.state.value}
onChange={()=> {this.setState({value:e.target.value })}}
Good question. I'm having the same issue, and just found a solution.
The problem is that:
You can't just use the default state of the modal component to set the initial input value, because the modal renders one time within the parent component (starting off invisible), so the default state of the Modal wont keep up with any changes to the 'pre-filled' info in the store that the inputs within the modal require access to.
You can't use the value attribute of the input to reference some redux store prop, since this is needed to reference the onChange function so the user can make changes to that pre-filled info.
And, you can't use the onChange function to set the initial value, because it is required to update the local state with the users changes - not set an initial value. Anyway, this requires the user to click on something, and you want the modal inputs to be pre-populated before the user does anything as soon as the modal opens...
So. What we need is to update these input fields every time the Modal attribute isModalOpen (or whatever you are using) changes.
(ie, pre-populate the fields when the Modal is opened).
Again, note that opening the Modal is not RENDERING the modal, it was already rendered, once, and has sat there being invisible until that isModalOpen attribute changed to true.
The Solution:
Step 1: make a handler function in the Modal component that prefills the inputdata by updating the local state of the Modal component. Mine looks like this :
handlePreFillModalInputsOnOpen = () => {
this.setState(() => ({
orthForm: this.props.matchLexUnit['orthForm'],
orthVar: this.props.matchLexUnit['orthVar'],
oldOrthForm: this.props.matchLexUnit['oldOrthForm'],
oldOrthVar: this.props.matchLexUnit['oldOrthVar'],
source: this.props.matchLexUnit['source'],
namedEntityCheck: this.props.matchLexUnit['namedEntityCheck'],
styleMarkingCheck: this.props.matchLexUnit['styleMarkingCheck'],
artificialCheck: this.props.matchLexUnit['artificialCheck'],
error: ''
}));
};
Step 2: Make that function fire ONLY when the isOpen attribute of the modal changes from false to true.
(This is the meat of your problem I think).
Use the lifecycle method componentDidUpdate. This will execute every time the props of the modal change.
componentDidUpdate(prevProps) {
if (this.props.isModalOpen === true && prevProps.isModalOpen === false) {
this.handlePreFillModalInputsOnOpen();
}
}
Watch out
make sure that you have a conditional in componentDidUpdate, otherwise you can run into infinite-loop/performance issues
if you have the possibility of null values icoming in as the prefilled input info, make a null-check so that they will not be passed into the local state.
Hope this helps :)
How to Programmatically Prefill, Fill or Update input fields value in React or useState Hooks?
Firstly - Get and define the data from database
const **yourData** = isDataFromDatabase;
or if the data is stored in Redux, then...
const **yourData** = useSelector(isDataFromDatabase);
Secondly - append it as the default value of a useState hook
const [isDataValue, setIsDataValue] = useState(**yourData**);
Thirdly - create a function to watch and Update the changes made by the user to your data value and set it to the useState hook created above
/** handles Your Data Value */
const handleDataValue = (text) => {
setIsDataValue(text);
};
Lastly - in your input tag, use the useState State as the "Value" parameter so it can be updated with the onChange function
<input
className="css"
id="myDataInput"
type="text"
value={isDataValue}
placeholder={isDataValue}
onChange={(e) => handleDataValue(e.target.value)}
/>
Now when you load the component, the prefilled value will be shown and can be updated in the HTML Input field.
That's All.

How do I go from one field to the next (without using TAB) in Redux-form 6?

I've got a form with three fields that make up a phone number input. It looks something like this:
<form>
<Field id="areaCode" name="areaCode" component={areaCode} max={3} type="text" />
<Field id="firstThree" name="firstThree" component={firstThree} max={3} type="text" />
<Field id="lastFour" name="lastFour" component={lastFour} max={4} type="text" />
</form>
The component for each Field looks like this (they are similar so I'll just show one to illustrate my point)
const areaCode = (field) => (
<input
{...field.input}
maxLength={field.max}
type="text"
onChange={(value) => {
// switch to next field (firstThree)
// after this field's length is >= 3
}}
/>
)
I want to automatically switch to the second field after the user has inputted 3 numbers in the first field. How does one switch to the next field programmatically?
I'm not sure how to reference the second field in the form to switch to when they blur away from the first field.
Am i doing this the right way? Should I be using Fields instead of Field?
Edit: To automatically switch to the next field upon hitting the maxLength, you could use onChange() and ref. The onChange() handler checks if the current input is at its max length. If it is, focus() on the next ref'd input on your react page.
Example: jsfiddle.net/4np9u17g/11
You should not need any sort of onBlur() function or have code to handle switching to the next input upon clicking tab. The browser will automatically focus on the input upon clicking tab.
It looks like you are using redux-form's Field correctly - you have defined a separate component for each part of the phone number, so you should use Field for each component (as you have already done). If, instead, you wanted to combine all of these inputs into one component, then you would need to use Fields. But, as you are now, you should be good.

Categories

Resources