Getting undefined instead of Input Field value - javascript

import { useState } from "react";
import "./styles.css";
function App() {
const [InputVal, setInputVal] = useState();
const [ShowDiv, setShowDiv] = useState(
<div>
<p>Hello world. This is default "Show Div" value</p>
</div>
);
const ChangeDivFunc = () => {
setShowDiv(
<div>
<p style={{ color: "red" }}>
Hello World. This is updated "Show Div" value
</p>
<input onChange={getInputval} type="text" />
<br />
<br />
<button onClick={AlertVal}>Show Input Value</button>
</div>
);
};
const getInputval = (val) => {
setInputVal(val.target.value);
};
const AlertVal = () => {
alert(InputVal);
};
return (
<div className="App">
<h1>Example</h1>
<br />
<button onClick={ChangeDivFunc}>Change Div</button>
{ShowDiv}
</div>
);
}
export default App;
Code Flow:
Click Change Div button then it will show Input field and Show Input Value button.
Now, Enter some value in input field and click the Show Input Value button to get the value of input field.
Problem:
It returns undefined instead of input field value.
I'm trying to get the value of Input field when Show Input Value button is clicked. But I'm not getting the desired results.
Here's the Sandbox link : Click for Code

Do not store html node inside state. You can simply store only a boolean value to switch between what node to show. I'm not pretty sure but it may cause weird behavior since React internally depends heavily on the DOM/HTML UI Tree (see Managing State).
Try this instead:
import { useState } from "react";
import "./styles.css";
function App() {
const [inputVal, setInputVal] = useState(""); // initialize as empty string.
const [showDiv, setShowDiv] = useState(false);
const changeDivFunc = () => {
setShowDiv(true);
};
const getInputVal = (event) => { // The arg is Event object, not val
setInputVal(event.target.value);
};
const alertVal = () => {
alert(inputVal);
};
return (
<div className="App">
<h1>Example</h1>
<br />
<button onClick={changeDivFunc}>Change Div</button>
{
showDiv? (
<div>
<p style={{ color: "red" }}>
Hello World. This is updated "Show Div" value
</p>
<input value={inputVal} onChange={getInputVal} type="text" />
<br />
<br />
<button onClick={alertVal}>Show Input Value</button>
</div>
) : (
<div>
<p>Hello world. This is default "Show Div" value</p>
</div>
)
}
</div>
);
}
export default App;
Forked Codepen

Related

onClick function is not called after I have enabled the button in Reactjs

I have a textarea and a button. The button is disabled by default and when the user starts typing, I enable the button to be clicked. But the problem is that, the onClick function is not called while already disabled = false was set.
I've seen this: button onClick doesn't work when disabled=True is initialized (Reactjs)
Seems to be a good idea, but after I setState with the new value, my component is re-rendering, and I don't really want that.
const refText = useRef(null);
const refBtn = useRef(null);
function handleBtnStatus(e) {
let text = e.target.value;
if(text.replace(/\s/g, "").length > 0) {
refBtn.current.disabled = false;
}
else {
refBtn.current.disabled = true;
}
}
function postThis() {
console.log("You posted! Text:", refText.current.value);
// disable again
refBtn.current.disabled = true;
// delete previous text wrote
refText.current.value = "";
}
return (
<>
{isLogged && (
<div className="container">
<div className="content">
<div className="utool-item-text">
<textarea name="textArea" placeholder="Write something.." ref={refText} onChange={(e) => handleBtnStatus(e)}></textarea>
</div>
<div className="utool-item-post">
<button className="ust-btn-post" ref={refBtn} disabled={true} onClick={postThis}>Da Tweet</button>
</div>
</div>
<div className="posts-section">
<div className="list-posts">
{posts.map((p) => {
return (p.hidden === false ? (
<div className="post" key={p.id}>
<div className="post-text">
<span>{p.text}</span>
</div>
</div>
) : (''))
})}
</div>
</div>
</div>
)}
</>
)
Any help?
Use state instead of refs, re-rendering is ok for your case
Simplified example:
import React, { useState } from 'react';
const SimpleExample = () => {
const [textAreaValue, setTextAreaValue] = useState('');
return (
<>
<button disabled={!textAreaValue} onClick={() => console.log('onClick handler')}>
click me
</button>
<textarea value={textAreaValue} onChange={(e) => setTextAreaValue(e.target.value)} />
</>
);
};
And I would recommend checking this Use state or refs in React.js form components?

How to add and remove multiple checkbox values and update nested array in React state hook

I am using React Context to create a multistep form, the form must keep the selection when the user clicks the next or previous step. I am using the below code and it's working fine until I reach the stage to add multiple features using the checkbox, once items are checked, user can go to the previous step to edit and press next to go to the next stage where checked checkboxes must remain checked. I cannot figure out how to push each checkbox value to the features array and remove the item from array when the user uncheck. The important part is to retain the selected despite user go to previous or next step.
Context Provider
import React, { useEffect, useState, createContext } from 'react'
const carSpecs = {
make: '', features: [],model: '',serviceHistory: false, warranty: false, trim: '', bodyType: '', transmission:''
}
export const UsedCarListingContext = createContext({})
export function GlobalUsedCarListingProvider (props) {
const [usedCar, setUsedCar] = useState(carSpecs)
useEffect(() => {}, [usedCar])
return (
<UsedCarListingContext.Provider
value={[usedCar, setUsedCar]}
>
{props.children}
</UsedCarListingContext.Provider>
)
}
Car Details Component
export const UsedCarAdDetails = () => {
const [usedCar, setUsedCar] = useContext(UsedCarListingContext)
const changeHandler = (e) => {
const {name, value} = e.target
setUsedCar({
...usedCar,
[name]: value
})
}
const handleChange = ({target: {name, checked}}) => {
setUsedCar({
...usedCar,
[name]: checked
})
}
return (
<div className="container-1100 bg-white shadow-nav-bar w-full h-52 pt-12">
<NavLink to={'/'} className='landing-nav-logo'>
<img
className='mr-20 mt-4 w-66 ottobay-logo-center'
src={OttobayGray}
alt={'logo'}
/>
</NavLink>
</div>
<div className="container-1050 mg-0auto flex justify-between mt-48">
<div className='container-700 p-20'>
<form>
<div className='ad-listing-input-wrapper mb-16-mobile mb-16 w-full-mobile flex items-center'>
<div className='ad-label-container'>
<label className="listing-input-label font-semibold mr-40"
htmlFor="videoLink">History: </label>
</div>
<div className="ad-input-group-container">
<div className='checkbox-group-container'>
<CheckboxWithImage
onChange={handleChange}
name={'serviceHistory'}
checked={usedCar.serviceHistory}
label={'Service History'}
icon={<GiAutoRepair/>}
checkboxTitleClass={'historyCB'}
/>
<CheckboxWithImage
onChange={handleChange}
name={'warranty'}
checked={usedCar.warranty}
label={'Warranty'}
icon={<AiOutlineFileProtect/>}
checkboxTitleClass={'historyCB'}
/>
</div>
</div>
</div>
<div>
<div className='checkbox-group-wrapper'>
{carFeatures.map(item => (
<div className='feature-item'>
<Checkbox
label={item.name}
onChange={handleFeaturesChange}
checked={usedCar && usedCar.features.some(val => val === item.id)}
value={item.id}
/>
</div>
))}
</div>
</div>
<div className="error-container"></div>
</div>
<div className="car-basic-submission-container">
<div> </div>
<button type='submit' className='search-button bg-button-primary text-white font-semibold rounded-4'> Next Step</button>
</div>
</form>
</div>
)
}
You seem to be calling a non existent function handleFeaturesChange in you feature-item checkbox.
Anyway, something like this should work:
const handleFeaturesChange = ({target: {value, checked}}) => {
setUsedCar({
...usedCar,
features: checked ? [
...usedCar.features,
value, // add the value to previously selected features
] : usedCar.features.filter(val => val !== value) // remove the value
})
}
You could potentially replace the value with name string but then you'd need to update the condition in the checked param of the Checkbox to compare it with the name instead.

Can event Handler propagate between events

please need your help to more understand this point, what I'm trying to do is to edit the task after posting it adding flag if the task needs to be edited or not with 'edit' flag
always give me the following error You provided a value prop to a form field without an onChange handler. This will render a read-only field. If the field should be mutable use defaultValue. Otherwise, set either onChange or readOnly
could me to solve that error , please
so App.js:
const App=()=> {
const [tasks,settasks]=useState([])
// const [title,setTitle] = useState('')
const AddHandler=(new_task)=>{
const new_arr = [...tasks,new_task]
settasks(new_arr)
}
const onKeyDownHandler=(event,taskIndex)=>{
if(taskIndex){
console.log('test')
}else{
const new_task = {'title':event.target.value,'edit':false}
if(event.keyCode === 13){
AddHandler(new_task)
}
}
}
const deleteHandler=(taskIndex)=>{
const new_tasks = [...tasks]
new_tasks.splice(taskIndex,1)
settasks(new_tasks)
}
const EditHandler=(editIndex) => {
const new_tasks = [...tasks]
new_tasks[editIndex].edit= true
settasks(new_tasks)
}
return (
<div className={classes.App}>
<h3>To do List ...</h3>
<div className={classes.Form}>
<Input inputtype="text" typing={onKeyDownHandler} />
<Button>Add</Button>
</div>
<Tasks
tasks={tasks}
edit={EditHandler}
typing={onKeyDownHandler}
delete={deleteHandler}/>
</div>
);
}
export default App;
in tasks.js:
const Tasks=(props)=>{
return(
<div>
{props.tasks.map((task,index)=>(
<Task triggeredit={task.edit}
key={index}
index={index}
click={()=>props.delete(index)}
edit={()=>props.edit(index)}
title={task.title}
typing={props.typing}
address={index}
/>
))}
{/*<input onKeyDown={(event)=>props.typing(event,1)}/>*/}
</div>
)
}
export default Tasks
in task.js:
const Task=(props)=>{
return (
<div className={classes.Task}>
<Input inputtype="checkbox" inputstyle='CheckBox'/>
{props.triggeredit ?
<Input
index ={props.index}
inputtype="text"
value={props.title}
typing={props.typing}/>:<p>{props.title}</p>}
<Button click={props.edit}><i className="fa fa-edit"></i></Button>
<Button click={props.click} style="Danger"><i className="fa fa-trash" aria-hidden="true"></i></Button>
</div>
)
}
export default Task
in Input.js:
const Input =(props) => {
let InputHtml = null
switch (props.inputtype) {
case('text'):
InputHtml = <input placeholder="Add Your Tasks"
type="text"
value={props.value}
onKeyDown={(event)=>props.typing(event,props.index)}
className={classes.InputElement}
ref={props.refs}
/>
break
case ('checkbox'):
InputHtml = <input type="checkbox" className={classes.InputElement}/>
break
default:
InputHtml = <input placeholder="Add Your Tasks" type="text" className={classes.InputElement}/>
break
}
return (
<div className={[classes.Input,classes[props.inputstyle]].join(' ')}>
{InputHtml}
</div>
)
}
export default Input

Get prop value from div in React

A working example of my problem can be found at:
https://codepen.io/RyanCRickert/pen/vYYQeaW
I am prop drilling a function two levels and passing that function along with an index to a rendered component. When a name is submitted it renders a new component which shows the name and div which has an onClick (X). I am trying to receive the index of where the name is located in the array which it lives so that I may splice it out when the button is clicked.
If I enter the name "Bob" for example, then click the div with the listener I can console log the event.target. Using the above example I get "<div class='person-item__X' value='0'>X</div>" for event.target and undefined for event.target.value. The value is being assigned as <div onClick={props.removeName} class="person-item__X" value={props.value}>X</div>.
Am I just unable to grab the value of a div in such a manor? Or is there something that I am missing? Thank you
Change these to your code
const PersonListItem = props => (
<div class="person-item">
<div class="person-item__name">{props.name}</div>
<div onClick={() => props.removeName(props.value)} class="person-item__X" value={props.value}>X</div>
</div>
);
Inside PeopleList replace this line
<PersonListItem key={index} name={person} value={index} removeName={(id) => props.removeName(id)} />
Inside TeamGenerator replace this line
<PeopleList people={this.state.names} removeName={(id) => this.handleRemoveName(id)} />
now in handleRemoveName you will recieve a id of the item on which X was clicked
handleRemoveName = id => {
const currentArr = this.state.names;
console.log(id);
}
In your case, to grab the value inside this div, you should use ref API.
Your code should look like this:
TeamGenerator.js
import React, { Component } from "react";
import CustomModal from "./Modal";
import PeopleList from "./PeopleList";
import "./index.css";
export default class App extends Component {
constructor(props) {
super(props);
// Create a ref
this.divTextRef = React.createRef();
this.state = {
names: [],
selectedName: ""
};
}
handleCloseModal = () => {
this.setState({
selectedName: ""
});
};
handleChange = e => {
this.setState({ name: e.target.value });
};
handleRemoveName = index => {
// Get your name and index this way
console.log("Your text: ", this.divTextRef.current.innerHTML);
console.log("Your index: ", index);
};
handleSubmit = e => {
e.preventDefault();
const currentNames = this.state.names;
if (this.state.name)
currentNames.push(
this.state.name[0].toUpperCase() + this.state.name.slice(1)
);
this.setState({
name: "",
names: currentNames
});
};
render() {
return (
<div className="container">
<CustomModal
selectedName={this.state.selectedName}
closeModal={this.handleCloseModal}
/>
<form onSubmit={this.handleSubmit}>
<label>
Add name:
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
<div className="people-list-container">
<PeopleList
people={this.state.names}
removeName={this.handleRemoveName}
upperRef={this.divTextRef} // Pass the ref down from your Component tree
/>
</div>
</div>
);
}
}
PeopleList.js
import React from "react";
import PersonListItem from "./PersonListItem";
export default class PeopleList extends React.Component {
render() {
return (
<div className="people-container">
<div className="people-title">List of people</div>
<div className="people-list">
{this.props.people.length === 0 ? (
<div className="people-item">
<span>No people added</span>
</div>
) : (
this.props.people.map((person, index) => (
<PersonListItem
key={index}
name={person}
value={index}
removeName={() => this.props.removeName(index)} // Passing index to the removeName function of Parent
upperRef={this.props.upperRef} // Continue passing it down to PersonListItem
/>
))
)}
</div>
</div>
);
}
}
PersonListItem.js
import React from "react";
const PersonListItem = props => (
<div className="person-item">
<div ref={props.upperRef} className="person-item__name"> // Use the passed ref
{props.name}
</div>
<div
onClick={props.removeName}
className="person-item__X"
value={props.value}
>
X
</div>
</div>
);
export default PersonListItem;
The div node does not have the value like input, so you can not grab it by your old way.

React not updating text (issue with .getDOMNode())

I'm using React to make a Markdown previewer and trying to make sense of what was used here to make the right box update with a live preview as soon as the text is changed on the left. They have this code at the bottom:
var RawInput = React.createClass({
update:function(){
var modifiedValue=this.refs.inputValue.getDOMNode().value;
this.props.updateValue(modifiedValue);
},
render:function(){
return (<textarea rows="22" type="text" ref="inputValue" value={this.props.value} onChange={this.update} className="form-control" />)
}
});
I implementing this in my code:
const InputText = React.createClass ({
update() {
let newValue = this.refs.inputValue.getDOMNode().value;
this.props.updateValue(newValue);
},
render() {
return (
<div>
<textarea
id="input-text"
rows="18"
type="text"
ref="inputValue"
value={this.props.value}
onChange={this.update}
/>
</div>
);
}
});
The app runs fine except that there is no live preview and the text on the right doesn't update. In the console I get this error: this.refs.inputValue.getDOMNode is not a function .
Here is the full code:
import React from 'react';
import Banner from './components/Banner.jsx';
import ContainerHeader from './components/ContainerHeader.jsx';
import marked from 'marked';
const App = React.createClass ({
updateValue(newValue) {
this.setState ({
value: newValue
})
},
getInitialState() {
return {
value: 'Heading\n=======\n\nSub-heading\n-----------\n \n### Another deeper heading\n \nParagraphs are separated\nby a blank line.\n\nLeave 2 spaces at the end of a line to do a \nline break\n\nText attributes *italic*, **bold**, \n`monospace`, ~~strikethrough~~ .\n\nShopping list:\n\n * apples\n * oranges\n * pears\n\nNumbered list:\n\n 1. apples\n 2. oranges\n 3. pears\n'
}
},
markup(value) {
return {__html: value}
},
render() {
return (
<div>
<Banner />
<div className="container">
<div className="row">
<div className="col-xs-12 col-sm-6">
<ContainerHeader text="I N P U T" />
<InputText
value={this.state.value}
updateValue={this.updateValue} />
</div>
<div className="col-xs-12 col-sm-6">
<ContainerHeader text="O U T P U T" />
<div id="output-text">
<span dangerouslySetInnerHTML={this.markup(marked(this.state.value))}></span>
</div>
</div>
</div>
</div>
</div>
);
}
});
const InputText = React.createClass ({
update() {
let newValue = this.refs.inputValue.getDOMNode().value;
this.props.updateValue(newValue);
},
render() {
return (
<div>
<textarea
id="input-text"
rows="18"
type="text"
ref="inputValue"
value={this.props.value}
onChange={this.update}
/>
</div>
);
}
});
export default App;
Any help welcome on solving this, and thanks!
Since version 15.* in React this.refs.inputValue refers to DOMElement, so you don't need use getDOMNode;
this.refs.inputValue.value
However, I think in this case you don't need use refs, as you call update inside onChange event, you can get target(refer to textarea) from event object, and from target get value
update(e) {
this.props.updateValue(e.target.value);
},
The example is using React v0.14.x which was one combined module.
From React v15 (0.15, but they changed to use it as the major) the methods and classes were split into two modules, React and ReactDOM.
You need to import and use ReactDOM.findDOMNode(component), documentation for which can be found here.
You actually do not need this.refs.inputValue
update(e) {
this.props.updateValue(e.target.value);
},

Categories

Resources