Passing function value from parent to child - javascript

I'm building a check builder, I have multiple Parent components (forms) that display their inputs on a Child component (check layout).
This is my parent component:
import React from 'react';
import './../App.css';
import Check from './Check';
class BusinessAddress extends React.Component {
constructor(props) {
super(props);
this.state = {text: {
name: 'BusinessAddress',
a: '',
b: '',
c: '',
d: '',
e: '',
f: '',
g: '',
h: ''
}};
}
handleComponentName = name => {
//console.log('handleComName', name)
return this.state.name === name;
}
handleChange(property, event) {
console.log(event.target.value);
const text = {...this.state.text};
text[property] = event.target.value;
this.setState({text: text});
}
handleSubmit(event) {
console.log(this.state.text.e);
}
render() {
return (
<div>
<div className="form-box">
<h3>Business Address</h3>
<label>Business Name</label>
<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={this.handleChange.bind(this, 'a')} maxLength="30" />
<label>Name Line 2</label>
<input type="text" placeholder="Business Name Line 2" value={this.state.text.b} onChange={this.handleChange.bind(this, 'b')} maxLength="90" />
<label>Street Address</label>
<input type="text" placeholder="Street Address" value={this.state.text.c} onChange={this.handleChange.bind(this, 'c')} maxLength="30" />
<label>Address Line 2</label>
<input type="text" placeholder="Street Address Line 2" value={this.state.text.d} onChange={this.handleChange.bind(this, 'd')} maxLength="30" />
<label>City</label>
<input type="text" className="short" placeholder="City" value={this.state.text.e} onChange={this.handleChange.bind(this, 'e')} maxLength="30" />
<label>State</label>
<input type="text" className="short" placeholder="State" value={this.state.text.f} onChange={this.handleChange.bind(this, 'f')} maxLength="30" />
<label>Postal</label>
<input type="text" className="short" placeholder="Postal" value={this.state.text.g} onChange={this.handleChange.bind(this, 'g')} maxLength="30" />
<label>Phone (optional)</label>
<input type="text" className="short" placeholder="Phone" value={this.state.text.h} onChange={this.handleChange.bind(this, 'h')} maxLength="30" />
</div>
<Check data={this.state.text} handleParent={this.handleComponentName}/>
</div>
)
}
}
export default BusinessAddress;
This is my child component:
import React from 'react';
import './../App.css';
export class Check extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
const data = Object.values(this.props.data);
if(this.props.handleParent('BusinessAddress')) {
}
return (
<div>
{ data.map((item, index) => <li key={index}>{item}</li>) }
<div id="Address"></div>
<div id="Bank-Info"></div>
</div>
)
}
}
export default Check;
I'm trying to map the data to a specific div based on which parent the data is coming from. Right now all that I'm getting from the child is the returned function, but no return value?
Thanks in advance!

<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={this.handleChange.bind(this, 'a')} maxLength="30" />
Change this to this
<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={(e) => this.handleChange(e, 'a')} maxLength="30" />
also change this
handleComponentName = name => {
//console.log('handleComName', name)
return this.state.name === name; }
to
this.state.text.name === name;
here is the demo

Try binding the onchange like
onChange={(event) => this.handleChange('h', event)}

Related

Create a reusable Form Input component with React & TypeScript

How can I define input attributes in typescript? I have an AddUser Component and TextInput Component, I want to import the TextInput component inside the AddUser component and then pass props to the TextInput component.
AddUser.tsx
import Button from '../Shared/Form/Button/Button';
import Form from '../Shared/Form/Form';
import TextArea from '../Shared/Form/TextArea/TextArea';
import TextInput from '../Shared/Form/TextInput/TextInput';
const AddUser = () => {
return (
<div>
<h1>Add User</h1>
<Form method="post" className={'user-form'}>
<TextInput label={'Name'} type="text" name="name" required />
<TextInput label={'Email'} type="email" name="email" required />
<TextInput label={'Country'} type="text" name="country" required />
<TextInput label={'Phone'} type="text" name="phone" required />
<TextArea label={'Address'} name="address" cols="30" rows="4" />
<div className="form-button">
<Button type={'submit'} className={'btn-add'}>
Add
</Button>
<Button type={'submit'} className={'btn-close'}>
Cancel
</Button>
</div>
</Form>
</div>
);
};
export default AddUser;
TextInput.tsx
const TextInput = ({ className, label, ...rest }: { className: string; label: string }) => {
return (
<div className={`${className} form-field`}>
<label htmlFor={label}>{label}</label>
<input {...rest} />
</div>
);
};
export default TextInput;
You can extend HTMLProps which comes with react:
import { HTMLProps } from "react";
interface MyCOmponentProps extends HTMLProps<HTMLInputElement> {
{...}
}
This is how we can make a reusable component. maybe I missed something in onChangeAction according to type script. please let me know me in the comment section so that i can help you better
Example codesandbox
const AddUser = () => {
return (
<div>
<h1>Add User</h1>
<form method="post" className={"user-form"}>
<TextInput
label={"Name"}
placeholder="Name"
type="text"
name="name"
required
/>
<TextInput
label={"Email"}
placeholder="Email"
type="email"
name="email"
required
/>
<TextInput
label={"Country"}
placeholder="Country"
type="text"
name="country"
required
/>
<TextInput
label={"Phone"}
placeholder="Phone"
type="text"
name="phone"
required
/>
</form>
</div>
);
};
export default AddUser;
const TextInput = ({
className,
label,
value,
type,
onChangeAction,
placeholder
}) => {
return (
<div className={`${className} form-field`}>
<label htmlFor={label}>{label}</label>
<input
placeholder={placeholder || "Text"}
type={type || "text"}
value={value}
onChange={onChangeAction}
/>
</div>
);
};

I want to redirect to a new page on react on a conditon

Error:Line 33:13: Expected an assignment or function call and instead saw an expression no-unused-expressions
I used the Route and Browser Router to create the link to the page.
I need to redirect to the home page on signing in.
import axios from 'axios'
import {Redirect} from 'react-router-dom'
import React,{Component} from 'react'
const url ="http://localhost:80/phpfile"
class Signup extends Component{
constructor(){
super();
this.state={
username:"",
password:"",
value:false
}
}
sign=e=>{
e.preventDefault();
const user={
"username":this.state.username,
"password":this.state.password
}
axios.post(url,user,{"header":{ "content-type": "application/json",}}
)
.then(result=>{if (result.data===true)
{
this.setState({value:true});
}
})
if(this.state.value){
<Redirect to='/'/>
}
}
render(){
const value= this.state.value;
return(
<div>
<form action="#">
<label> Username</label>
<input name="name" value="Enter the usrname" id ="name"
onChange={e => this.setState({ username: e.target.value })}/>
<label>Password</label>
<input type="password" placeholder="Enter Password" id="pass"
name="pass" onChange={e => this.setState({password: e.target.value })}/>
<botton onClick={e=>this.sign(e)}>Signin</botton>
</form>
</div>
)
}
}
export default Signup;
As you are not using state anywhere, you can add redirect instead of setting state:
...
.then(result=>{if (result.data===true)
{
return <Redirect to='/'/>
}
})
or if state requirement is there, then based on state you can add the Redirect in return statement of component
render(){
const value= this.state.value;
return(
<div>
{!value ?
(<form action="#">
<label> Username</label>
<input name="name" value="Enter the usrname" id ="name"
onChange={e => this.setState({ username: e.target.value })}/>
<label>Password</label>
<input type="password" placeholder="Enter Password" id="pass"
name="pass" onChange={e => this.setState({password: e.target.value })}/>
<botton onClick={e=>this.sign(e)}>Signin</botton>
</form>)
: (<Redirect to='/'/>)
}
</div>
)
}

Adding array elements through multiple form fields in React

I am working on a quiz app project to learn to react. I came across a situation where I need to store incorrect options in a quiz question in an array. And later pass over the information to the database.
This is an example JSON format.
{
incorrect_answers:["Jeff Bezos","Satya Nadela","Bill Gates"] }
The incorrect answer is an array and the value needs to be inputted through separate text boxes for each incorrect option like this.
option input form
The part where I am stuck is appending them to the array here is my attempt.
export default class CreateQuiz extends Component{
constructor(props){
super(props);
this.onChangedIncorrectAnswer=this.onChangedIncorrectAnswer.bind(this);
this.onSubmit=this.onSubmit.bind(this);
this.state={
incorrect_answers:[]
}
}
onChangedIncorrectAnswer(e){
const option=e.target.value
this.setState({
incorrect_answers:[...this.state.incorrect_answers,option]
});
}
onSubmit(e){
e.preventDefault();
const quiz = {
incorrect_answers:this.state.incorrect_answers
}
console.log(quiz);
axios.post("http://localhost:3000/quizes",quiz)
.then(res=>console.log(res.data));
window.location='/quiz-list';
}
render(){
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Incorrect Option 1</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<input type="submit" value="Submit Quiz" className="btn btn-primary"/>
</div>
</form>
</div>
)
}
}
But the form was not working as expected. When I enter content for the first option in the "Option 1" text box only the first character is stored remaining in "Option 2" and so on.
try this, this would work!!
export default class CreateQuiz extends Component {
constructor(props) {
super(props);
this.onChangedCorrectAnswer = this.onChangedCorrectAnswer.bind(this);
this.onChangedIncorrectAnswer = this.onChangedIncorrectAnswer.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
category: "",
correct_answer: "",
difficulty: "",
type: "",
question: "",
incorrect_answers: ["", "", ""]
};
}
onChangedCorrectAnswer(e) {
this.setState({
correct_answer: e.target.value
});
}
onChangedIncorrectAnswer(e, index) {
const option = e.target.value;
const { incorrect_answers } = this.state;
incorrect_answers[index] = option;
this.setState({
incorrect_answers
});
}
onSubmit(e) {
e.preventDefault();
const quiz = {
category: this.state.category,
correct_answer: this.state.correct_answer,
incorrect_answers: this.state.incorrect_answers,
difficulty: this.state.difficulty,
type: this.state.type,
question: this.state.question
};
console.log(quiz);
axios
.post("http://localhost:3000/quizes", quiz)
.then((res) => console.log(res.data));
window.location = "/quiz-list";
}
render() {
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Correct Answer</label>
<input
type="text"
required
className="form-control"
value={this.state.correct_answer}
onChange={this.onChangedCorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 1</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 0)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 1)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 2)}
/>
</div>
<div className="form-group">
<input
type="submit"
value="Submit Quiz"
className="btn btn-primary"
/>
</div>
</form>
</div>
);
}
}
Your array state is considered as one state only
Why don't you create state on the go when user do any change in the input.
create a state object like
this.state = {incorrect_answers: {}}
In your onChangedIncorrectAnswer
onChangedIncorrectAnswer(e){
const option=e.target.value;
const stateName = e.target.name;
this.setState({
incorrect_answers: {...this.state.incorrect_answers, [stateName]: option }
});
}
use your form element as add name as unique which will be used as state
<div className="form-group">
<label>Incorrect Option 1</label>
<input name="incorrect_answers_0" type="text" required className="form-control" value={this.state.incorrect_answers[incorrect_answers_0]}
onChange={this.onChangedIncorrectAnswer} />
</div>
use that object while saving
onSubmit(e){
let yourIncorrectAnswers = Object.values(this.state.incorrect_answers);
})
}

Radio button global state for name attribute

I need to be able to have radion buttons or checkboxes to show / hide content if its checked. There will be more radio buttons and checkboxes to show content in the same form, so to distinguish them from each other, it could be based on the name attribute.
So far i can show the hidden fields when i check the radio buttons, but i want one to cancel out the other, but only if it has the same name attribute (something else can also work).
Is there a react genius who can figure this out? I would be forever in your debt :)
class PartnerRoute extends Component {
constructor(props) {
super(props)
this.state = {
showOneTimeFee: '',
showSubscription: ''
};
}
toggleOneTimeFee = () => {
const currentState = this.state.showOneTimeFee;
this.setState({
showOneTimeFee: !currentState
})
}
toggleSubscription = () => {
const currentState = this.state.showSubscription;
this.setState({
showSubscription: !currentState
})
}
render() {
return (
<div className="partner-route">
<ContentContainer>
<div className="form--create-event">
<form>
<h3>Event information</h3>
<GridContainer columnCount="one">
<CustomInput type="text" placeholder="Event name" />
</GridContainer>
<GridContainer columnCount="one">
<CustomTextarea type="text" placeholder="Event description" />
</GridContainer>
<h3>Event date</h3>
<GridContainer columnCount="three">
<CustomInput type="text" placeholder="Day" />
<CustomInput type="text" placeholder="Month" />
<CustomInput type="text" placeholder="Year" />
</GridContainer>
<h3>Payment</h3>
<GridContainer columnCount="one">
<CustomRadio
type="radio"
name="payment"
id="rb1"
value="1"
label="Free, no payment needed"
/>
<CustomRadio
type="radio"
name="payment"
id="rb2"
value="2"
label="1 time fee"
onChange={this.toggleOneTimeFee}
/>
{this.state.showOneTimeFee &&
<div className="hidden-field">
<CustomInput type="text" placeholder="Price" />
</div>
}
<CustomRadio
type="radio"
name="payment"
id="rb3"
value="3"
label="Subscription"
onChange={this.toggleSubscription}
/>
{this.state.showSubscription &&
<div className="hidden-field">
<CustomInput type="text" placeholder="Price" />
</div>
}
</GridContainer>
</form>
</div>
</ContentContainer>
</div>
)
}
}
export default PartnerRoute
Please check this example where I used setState with prevState that is important and also I used changeHandler for all three radio. Moreover, to run this code in my side I changed all Custom input with generic input for ex CustomInput to input. Please revert this your side.
import React, {Component} from "react";
export default class PartnerRoute extends Component {
constructor(props) {
super(props);
this.state = {
showOneTimeFee: false,
showSubscription: false
};
}
handleChange = (event) => {
if (event.target.value == 2) // One Time Fee
this.setState(prevState => {
return {
showOneTimeFee: !prevState.showOneTimeFee,
showSubscription: false
};
});
else if (event.target.value == 3) // Subscription
this.setState(prevState => {
return {
showOneTimeFee: false,
showSubscription: !prevState.showSubscription
};
});
else // Free, no payment needed
this.setState({
showOneTimeFee: false,
showSubscription: false
});
};
render() {
return (
<div className="partner-route">
<div>
<div className="form--create-event">
<form>
<h3>Event information</h3>
<div>
<input type="text" placeholder="Event name"/>
</div>
<div>
<input type="text" multiline="true" placeholder="Event description"/>
</div>
<h3>Event date</h3>
<div>
<input type="text" placeholder="Day"/>
<input type="text" placeholder="Month"/>
<input type="text" placeholder="Year"/>
</div>
<h3>Payment</h3>
<div>
<input type="radio" name="payment" id="rb1" value="1" label="Free, no payment needed"
onChange={this.handleChange}/>
<label htmlFor="rb1">Free, no payment needed</label><br/>
<input type="radio" name="payment" id="rb2" value="2" label="1 time fee"
onChange={this.handleChange}/>
<label htmlFor="rb2">1 time fee</label><br/>
{this.state.showOneTimeFee &&
<div className="hidden-field">
<input type="text" placeholder="One Time Price"/>
</div>
}
<input type="radio" name="payment" id="rb3" value="3" label="Subscription"
onChange={this.handleChange}/>
<label htmlFor="rb3">Subscription</label><br/>
{this.state.showSubscription &&
<div className="hidden-field">
<input type="text" placeholder="Subscription Price"/>
</div>
}
</div>
</form>
</div>
</div>
</div>
)
}
}

Handle change event not working for input types?

I am new to react… my handle change event is not working while typing text into an input. How do I go about fixing that? I want to handle both inputs with the same handle change.
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
var first_name = e.target.first_name
var last_name = e.target.last_name
var state = this.state
state[first_name] = e.target.value
state[last_name] = e.target.value
this.setState(state)
}
render() {
return (
<div>
<TextField hint text="First Name" id="user_first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="user_last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)
}
}
Based on id you should update the state and not both on them together. Try the below method. Also change the ids
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
this.setState({[e.target.id]: e.target.value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
as you're using material-ui/TextField component updating state by target.id can't work, because TextField component doesn't pass your id to its input, so you can do it by adding second parameter to your handleChange function, like this:
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(value, param){
this.setState({[param]: value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={(e) => this.handleChange(e.target.value, 'first_name')} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={(e) => this.handleChange(e.target.value, 'last_name')} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
I think, issue is you are updating both the fields by the same value, write it like this:
handleChange(e){
var obj = {}
obj[e.target.name] = e.target.value
this.setState(obj);
}
And assign the same name as the state variable names, like this:
<TextField ... name='first_name' value={this.state.first_name} onChange={this.handleChange.bind(this)}/>
<TextField ... name='last_name' value={this.state.last_name} onChange={this.handleChange.bind(this)} />
Use this:
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
let obj = {};
obj[e.target.name] = e.target.value;
this.setState(obj);
}
render() {
return (
<div>
<TextField hintText="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="first_name" size="30" type="text" value={this.state.first_name} />
<TextField hinText="Last Name" id="last_name" floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
class Settings extends React.Component {
constructor(props) {
super(props)
}
handleChange=(e)=>{
const {name,value}=e.target;
this.setState({[name]=value});
}
render() {
return (
<div>
<TextField hintText="First Name" floatingLabelFixed="editprofile" onChange={this.handleChange} name="first_name" size="30" type="text" />
<TextField hinText="Last Name"floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange} size="30" type="text"/>
</div>
)}
}

Categories

Resources