Why can't I change the value using my input? - javascript

I´m trying to change one value of my parent. My parent container send the data to PersonalComponent and PersonalComponent send the data to my AvatarComponent what is the component where I have my input
I receive the props in my PersonalComponent that's I know, but when I send the data to AvatarComponent, I think I can change the data of my container that's the parent of PersonalComponent
This is the parent of all:
class HandlePersonal extends Component {
state = {
...this.props.user
};
handleUsername = e => {
e.preventDefault();
this.props.dispatch({
type: "CHANGE_USERNAME",
payload: this.state.displayName
});
};
handleChange = e => {
this.setState({ ...this.state, [e.target.name]: e.target.value });
alert(2);
};
render() {
return (
<PersonalComponent
handleUsername={this.handleUsername}
handleChange={this.handleChange}
data={this.state}
/>
);
}
}
This is my PersonalComponent
const PersonalComponent = props => {
return (
<div id="personal">
<h2>My profile</h2>
<Card>
<div id="personal-container">
<div id="cover">
<CoverComponent />
</div>
<div id="avatar">
<AvatarComponent
data={props.data.photoURL}
onChange={props.handleChange}
/>
</div>
<div id="user-name">
<form onSubmit={props.handleUsername}>
<InputText
name="displayName"
value={props.data.displayName}
onChange={props.handleChange}
/>
<Button id="save-username" label="Ok" />
</form>
</div>
</div>
</Card>
</div>
);
};
I know that it's working because I had alert(props.data) inside PersonalComponent
And then, this is my AvatarComponent
<h1>Value: {props.data}</h1>
<input name="photoURL" value={props.data} onChange={props.handleChange} />
And here, if I alert(props.data) I receive null that's the actual value of photoURL in the HandlePersonal but I can't change the value using my input. Why?
I want to make that when i write in my input inside AvatarComponent the value of HandleContainer change

In short:
HandlePersonal.handleChange() needs to call this.setState('photoUrl': 'input value') to update the state.
Lemme knwo if you need detailed answer..im on my phone so not so convenient.
EDIT
<input name="photoURL" value={props.data} onChange={props.onChange} />
Because u pass it as onChange

Related

Why my form input is typing per 1 letter and then stop if passing props

I know this before but I forgot how did I do it..so basically let say I have
const [showItem,setShowItem] = useState({})
const [updateName,setUpdateName] = useState('')
and then I have a props function that will do something like this...this props is callable for array of items and I want to do this to make it more cleaner and reuseable.
<ItemsEdit items={showItem} setUpdateName_= { setUpdateName } updateName = { updateName } ></ItemsEdit>
Now as you see, when I'm trying to pass my setUpdateName_ and updatename.
UPDATE
This is the map for my items that will call the <ItemsEdit/> for specific id only in my buttons. (but this not affect anything in form)
{nfts.map((nft,i) => {
return(
<div
className="items"
key={nft.id}
>
{showItem.id == nft.id ? <>
<form onSubmit={handleSubmit}>
<ItemsEdit
items={showItem}
setUpdateName= { setUpdateName }
updateName = { updateName }
/>
</form>
</> : <>
<Items items={nft}></Items>
</>}
</div>
)
})}
and here is the <ItemsEdit/>
so for every key that I press it will lose the focus in input but when I used autoFocus = "autoFocus" in the input text it will works but the only thing is that it will the same text in other items..so its not the best idea for me.
const ItemsEdit = ({items,setUpdateName,updateName}) => {
return (
<>
<input
id='name'
type="text"
key="text"
// autoFocus="autoFocus"
value = {updateName}
placeholder="NFT name"
onChange={ e => setUpdateName( e.target.value )}
></input>
<p>{items.id}</p>
<img src={items.data.img} alt="" />
<div className="buttons">
<button
type='submit'>
Update
</button>
<button type='submit' className='left'
onClick={
() => {
setShowItem({})}
}>
<ion-icon name="arrow-back-circle-outline"></ion-icon>
</button>
</div>
</>
)
}
I now have an answer but this kinda nasty for me
so for the <ItemsEdit/> I would call it something like this
{ItemsEdit(
{items:showItem,
setUpdateName:setUpdateName,
updateName:updateName}
)}
and just remove the return of and change the { } into ( )just like this
const ItemsEdit = ({items,setUpdateName,updateName}) => (
)

React Form: How to add error message that disappear if the input was typed in

I already built the form in React and it shows the input fields in red borders that'll change to regular borders once someone types it in. I used this example from this React form article link So everything is working except I wanted to add the error message under the input field that displays "Please fill in the blank field" that will disappear once someone starts typing in the field. How do I do this?
Here's my code in Form.js:
import React, { Component } from 'react';
import FormField from './FormFieldBox';
function validate(name, isin) {
// true means invalid, so our conditions got reversed
return {
name: name.length === 0,
isin: isin.length === 0
};
}
export default class PopupForm extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
isin: '',
country: '',
errormessage: ''
}
}
updateInput = (e) =>{
this.setState({[e.target.name]: e.target.value})
}
closePopupSubmit = (e) => {
if (!this.canBeSubmitted()) {
e.preventDefault();
}
let security = { //1.gather security data from form submit
name: this.state.name,
isin: this.state.isin,
country: this.state.country
}
this.props.submitPopup(security); //2.closePopup function, add security data
}
canBeSubmitted() {
const errors = validate(this.state.name, this.state.isin);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return !isDisabled;
}
cancelPopupSubmit = (e) => {
e.preventDefault()
this.props.cancelPopup();
}
render() {
const errors = validate(this.state.name, this.state.isin);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return (
<div className='popup'>
<div className='popup-inner'>
<form onSubmit={this.closePopupSubmit}>
<FormField onChange={this.updateInput} className={errors.name ? "input error" : "input"} label="Name" type="text" name="name" value={this.state.name} />
<FormField onChange={this.updateInput} className={errors.isin ? "input error" : "input"} label="ISIN" type="text" name="isin" value={this.state.isin} />
<FormField onChange={this.updateInput} label="Country" type="text" name="country" value={this.state.country} />
<button type="button" onClick={this.cancelPopupSubmit} className="button">Cancel</button>
<button type="submit" className="button" disabled={isDisabled}>Submit</button>
</form>
</div>
</div>
)
}
}
And my component FormField.js
import React from "react";
const FormBox = props => {
return (
<div className="field">
<label className="label">{props.label}</label>
<div className="control">
<input onChange={props.onChange}
className={props.className}
type={props.type}
name={props.name}
value={props.value}
placeholder={props.placeholder} />
{/* {props.errormessage} */}
</div>
</div>
)
}
export default FormBox;
const FormBox = props => {
return (
<div className="field">
<label className="label">{props.label}</label>
<div className="control">
<input onChange={props.onChange}
className={props.className}
type={props.type}
name={props.name}
value={props.value}
placeholder={props.placeholder} />
</div>
{Boolean(props.value.length) || (
<div className="err-msg">
Please fill in the blank field
</div>
)}
</div>
)
}
There are two ways you can achieve this
First : oninvalid attribute in HTML5 and calling a custom function on that.
Second : along with each element name object in state have a length attribute. In validation function you can check for the length and throw a custom error that you want to display.

How to pass values from input to button react?

There is a field in which the static path of file formation is registered. I have made this field editable in case the user wants to change the path for the formation according to his desire.
<div className="w3-col l8 m8 s8">
<input
className="w3-input"
type="text"
name="file_name"
defaultValue={`${test_path}`}
disabled={false}
/>
</div>
Так же есть кнопка, при клике которой вызывается функция формирования файла по заданному пути
<Btn_enabled
func={() => create_file(`${test_path}.xmind`)}
name="Create file"
/>
How can I transfer the modified path by the user to the button?
You need to introduce a state for your input component.
And just reference it (by passing it through props, state manager, etc).
For example, input value state named value:
// With hooks
function InputValueToButton() {
const [value, setValue] = useState(testPath);
return (
<div className="App">
<input
onChange={e => setValue(e.target.value)}
type="text"
value={value}
/>
<Btn_enabled func={() => create_file(`${value}.xmind`)}/>
</div>
);
}
If you are using a version of React that does not support hooks, you can achieve the same thing using classes:
// React classes
class InputValueToButton extends React.Component {
state = {
value: testPath
};
render() {
return (
<div className="App">
<input
onChange={e => this.setState({ value: e.target.value })}
type="text"
value={this.state.value}
/>
<button>{this.state.value}</button>
</div>
);
}
}

React: generating input field data with a button component

I'm creating an intake form where a piece of data can be input into the text field, or generated randomly with a button next to the field.
I want to do this for 3 fields on the form so I created a component
called <RandomDataButton />
I'm stuck with how to make sure the results of the calculation done by the button component update the value of the text box so that the form submission contains the generated data.
I don't fully understand the state propagation, but what I do understand is that the flow is one way, down the hierarchy of components.
So what I am attempting to do is have a choice of inputting some data in the text box, or generating some random data from a button (I'd like to reuse it in other ui creations)
Where I am stuck is how do I update the input field from the componenet that is lower in the hierarchy.
Do I pass the state to the randomizer button and then have it update a copy of state? Or am I totally off base with that approach?
App:
class App extends React.Component {
render(){
return (
<div>
<DataInputForm />
</div>
);
}
}
DataInputForm:
class DataInputForm extends React.Component{
state= {
projectname: '',
datasource: '',
data1: '',
data2: '',
data3: '',
};
handleSubmit = e => {
e.preventDefault();
console.log({
projectname: this.projectname.value,
datasource: this.datasource.value,
data1: this.data1.value,
data2: this.data2.value,
data3: this.data3.value,
});
}
handleChange = e => this.setState({[e.target.name]: e.target.value});
render(){
return(
<form className="ui form" onSubmit={this.handleSubmit}>
<div className="field">
<label htmlFor="projectname">Project Name: </label>
<input
type="text"
id="projectname"
name="projectname"
placeholder="Project Name"
ref={input => this.projectname = input}
/>
</div>
<div className="field">
<label htmlFor="datasource">Data Source: </label>
<input
type="text"
id="datrasource"
name="datasource"
placeholder="Data Source"
ref={input => this.datasource = input}
/>
</div>
<div className="field">
<label htmlFor="data1">Data 1: </label>
<input
type="number"
min="3"
max="18"
id="data1"
name="data1"
ref={input => this.data1 = input}
/>
<RandomDataButton buttonid={"data1button"} buttonname={"Data1"} />
</div>
<div className="field">
<label htmlFor="data2">Data 2: </label>
<input
type="number"
min="3"
max="18"
id="data2"
name="data2"
ref={input => this.data2 = input}
/>
<RandomDataButton buttonid={"data2button"} buttonname={"Data2"} />
</div>
<div className="field">
<label htmlFor="data3">Data 3: </label>
<input
type="number"
min="3"
max="18"
id="data3"
name="data3"
ref={input => this.data3 = input}
/>
<RandomDataButton buttonid={"data3button"} buttonname={"Data3"} />
</div>
<button className="ui button" type="submit">Create Data</button>
</form>
);
}
}
RandomDataButton:
const getRandom = max => Math.floor(Math.random() * Math.floor(max));
class RandomDataButton extends React.Component {
generateData(value){
var result, destination;
destination = value.toLowerCase();
result = getRandom(1000);
console.log("Generated " + result + " for range of " + value + "]: " + destination);
//this.state.{destination};
}
render(){
return(
<button id={this.props.buttonid} type="button" onClick={this.generateData.bind(null,this.props.buttonname)}>{this.props.buttonname}</button>
//<button id="strbutton" type="button">Generate</button>
);
}
}
Pass a function as prop to RandomDataButton. Define the function in DataInputForm and use it update the state in DataInputForm by calling the prop function from RandomDataButton whenever you need the update.
It seems you are working with multiple components, so while working with multiple components, it is highly recommended to use any central storage container, which would be useful to get your desired data in any components
Flux and redux both are tested architectures for data state management, you could use any of them, I would recommend using redux.
Here's a codesandbox for your reference: https://codesandbox.io/s/bold-frog-01ff2
This is effectively a continuation of Amala's suggestion.
You are correct, the hierarchy is one-way. Which means we should define a function in DataInputForm (lvl2) and pass it as a prop to RandomDataButton (lvl3). That function is bound to DataInputForm's execution context, and we want to update it's state so we can feed the new data back into each individual input.
For example:
createRandomText = (associatedField, value) => {
this.setState(
{
[associatedField]: value
},
() => console.log(this.state)
);
};
So to update the state correctly, we need to provide a field corresponding to the right input, and a value (the randomized value).
We pass in that function as a prop to RandomDataButton and use it for the onClick() handler.
class RandomDataButton extends React.Component {
generateData = () => {
let result = getRandom(1000);
this.props.createRandomText(this.props.matchingInput, result);
};
render() {
return (
<button
id={this.props.buttonid}
type="button"
onClick={this.generateData}
>
{this.props.buttonname}
</button>
//<button id="strbutton" type="button">Generate</button>
);
}
}
Additionally we need to provide another prop to the button component so we can call the above function correctly:
<RandomDataButton
buttonid={"data1button"}
buttonname={"Data1"}
createRandomText={this.createRandomText}
matchingInput={"data1"}
/>
See sandbox for full details :)

How to get values from multiple Textareas in React

I have a form that has more than 1 textarea(3 to exact). The issue is that, if I type something in 1 textarea then the other textareas are also filled and updated. And I dont' want that. I'm using an onChange handler to make them controlled components but they're not behaving as expected. I've looked online but couldn't find a solution! How do I make them update individually on change/type?
React Textarea component
const Textarea = ({ labelText, placeholder, value, name, onChange }) => {
return (
<div className="textarea-panel">
<label>{labelText}</label>
<textarea
style={{ display: 'block' }}
cols="60"
rows="5"
placeholder={placeholder}
value={value}
name={name}
onChange={onChange}
/>
</div>
);
}
export default Textarea;
React Form component
import Textbox from './Textbox';
export class Form extends Component {
constructor(props) {
super(props);
this.state = {
data: {
career: '',
experience: '',
additionalInformation: '',
},
};
this.handleTextareaChange = this.handleTextareaChange.bind(this);
}
handleTextareaChange(event) {
this.setState({
data: {
[event.target.name]: event.target.value,
},
});
}
render() {
return (
<form>
<ul>
<li>
<Textbox
labelText="Write your career "
value={this.state.data.career}
placeholder="e.g. extra information"
name="career"
onChange={this.handleTextareaChange}
/>
<span>{this.state.data.career}</span>
</li>
<li>
<Textbox
labelText="Write your experience"
value={this.state.data.experience}
placeholder="e.g. extra information"
name="experience"
onChange={this.handleTextareaChange}
/>
<span>{this.state.data.experience}</span>
</li>
<li>
<Textbox
labelText="Additional information"
value={this.state.data.additionalInformation}
placeholder="e.g. extra information"
name="additionalInformation"
onChange={this.handleTextareaChange}
/>
<span>{this.state.data.additionalInformation}</span>
</li>
</ul>
</form>
);
}
}
export default Form;
You're overriding the entire state with a new key on the data object. Every time the onChange handler is called the entire state gets overriden with a new data object with the current textbox's name as the key. Instead just update the particluar key on the data like this
Try it here : Codesandbox
handleTextareaChange(event) {
const { data } = this.state
data[event.target.name] = event.target.value
this.setState({
data
});
}
Hope this helps !

Categories

Resources