Reactjs not able to render a component which has a form - reactjs

In my App.js, I have a class component Addition which will display 2 numbers and have a text box to get the result from the user. In the same file I have another class component App from which when I try to call <Addition/>, it renders the form perfectly as expected. However, I want the <Addition/> component to be triggered on a button click, which is not working.
class Addition extends Component{
render(){
return (
<form onSubmit={this.validateResult}>
<div >
<Box1 val={this.state.value1}/>
<Box1 val="+"/>
<Box1 val={this.state.value2}/>
<Box1 val="=" />
<input className="resbox"
value={this.state.result}
onChange={event => this.setState({result: event.target.value})}
required
/>
<br/>
<Box2 val={this.state.message} />
<br/><br/>
<input className="btn btn-info" type="submit" value="Submit" />
</div>
</form>
)
}
}
export default class App extends Component {
handleClick= (event) => {
event.preventDefault()
console.log("inside handleclick")
return (
<Addition />
);
}
render(){
return (
<div className="App">
<header className="row App-header">
<p >
KIDS MATHS
</p>
<div className="row col-2">
<button className="btn btn-lg offset-1" onClick={this.handleClick}> + </button>
</div>
</header>
</div>
)
}
}
When I tried to include the <Addition/> within the on-click event, the page simply remains same.
Please advice.

Everything you want to render has to called directly from within the render function. You can use conditional rendering to achieve to selective rendering of Addition. For this add a state member and set the value accordingly at the trigger point. This will call render again and the content will be shown as expected.
export default class App extends Component {
state = {
showAddition: false
}
handleClick= (event) => {
event.preventDefault()
console.log("inside handleclick")
this.setState({showAddition: true})
}
render(){
const { showAddition } = this.state
return (
<div className="App">
<header className="row App-header">
<p >
KIDS MATHS
</p>
<div className="row col-2">
<button className="btn btn-lg offset-1" onClick={this.handleClick}> + </button>
</div>
</header>
{showAddition && <Addition/>}
</div>
)
}
}
You can also consider to convert the components to function components and use useState instead of the state object. This will shorten the code a little bit.

Related

Conditionally Render parent component screen on child component a Form onSubmit() call. (w/ react-redux)

I have a parent component that displays a form when a button is clicked. This button marked (+) (see Image 1) will cause a "Create a new Course" child component to be displayed. I am trying to hide this child component after the user makes a "Create Course" submission (see Image 2).
Current method I am displaying here is to assigning a "onClick" functionin the child component form that triggers a parent function to toggle the form to hide. However, the child form apparently can't handle both a "onSubmit" function and "onClick" button function at the same time.
Any suggestions or advice would be most welcome.
Image 1
Image 2
PARENT COMPONENT
class ContentCreation extends Component {
constructor(props) {
super(props);
this.toggleCreateCourseFormOpen = this.toggleCreateCourseFormOpen.bind(this);
this.state = {
(...)
createCourseFormOpen: false, <---- USED TO INDICATE IF THE CHILD FORM SHOULD BE DISPLAYED OR NOT
(...)
};
}
//Toggles the "createCourseFormOpen variable from false to true; or from true to false//
toggleCreateCourseFormOpen() {
this.setState({createCourseFormOpen: !this.state.createCourseFormOpen})
}
render() {
(...)
return (
(...)
<div className='row center center-align'>
<h4>List of Your Courses</h4>
<div className='col l12 s12 m12'>
<button className='btn btn-floating custom-orange lighten-1' onClick={this.toggleCreateCourseFormOpen}>{this.state.createCourseFormOpen ? '-' : '+'}</button>
{this.state.createCourseFormOpen ? <CreateCourseForm triggerToggleCreateCourseFormOpen={this.toggleCreateCourseFormOpen} /> : ''}
{/* Passing down the courses from the courseReducer into the "CourseList" component. */}
<CourseList courses={courses}/>
</div>
</div>
</div>
)
}
(.... Rest Of Code ....)
CHILD (CreateCourseForm.js) COMPONENT
//Function used when user submits a create course request.
handleSubmit = (e) => {
e.preventDefault();
this.props.createCourse(this.state)
}
render() {
return (
<div className='container selection create-course green'>
<form onSubmit={this.handleSubmit} className='white'>
<h5 className='grey-text text-darken-3'>Create a new Course</h5>
{/* Input field for Course Name*/}
<div className='input-field'>
<label htmlFor='courseName'>Course Name</label>
<input type='text' id='courseName' onChange={this.handleChange}/>
</div>
{/* Input field for Course Details*/}
<div className='input-field'>
<label htmlFor='courseDescription'>Course Description</label>
<textarea className='materialize-textarea' id='courseDescription' onChange={this.handleChange}>
</textarea>
</div>
{/* Button used to create the new course.*/}
<div className='input-field'>
<button onClick={this.props.triggerToggleCreateCourseFormOpen} className='btn custom-orange lighten-1 z-depth-0'>Create Course</button>
</div>
</form>
</div>
)
}
}
(.... Rest of Code .... )
I think the best solution is to listen one event.
handleSubmit = (e) => {
e.preventDefault();
this.props.triggerToggleCreateCourseFormOpen(e)
this.props.createCourse(this.state)
}
If you want your code to work. You need to add the type(type="submit"):
<div className='input-field'>
<button type="submit" onClick={this.props.triggerToggleCreateCourseFormOpen} className='btn custom-orange lighten-1 z-depth-0'>Create Course</button>
</div>

Append data in same page in button click with react Js

How can we list data from the array list on the same page in button click using react?
When user enter quantity setting value text box change event
class ProductList extends Component {
constructor(props) {
super(props);
this.state={
CartArray:[],
ProductList:[],
}
}
handleInputChange = event =>
{
const cart_values = event.target.name.split('-');
let newCart = {};
newCart["Key"]=cart_values[0]
newCart["ProductName"]=cart_values[1]
newCart["ProductBrand"]=cart_values[2]
this.setState(prevState => ({CartArray: [...prevState.CartArray, newCart]}))
}
viewCart = () => {
//What need to write here show data from CartArray:[] to my basket
}
}
Below is my render method. Numerical text box change i am setting in state value
render() {
return (
<div className="card" style={{ marginBottom: "10px"}}>
<div> <button className="btn btn-sm btn-warning float-right" onClick={this.viewCart}>View cart</button></div>
{this.state.ProductList.map((product, key) =>(
<div className="card-body">
<div className="card-title" key={key} value={key}>{product.ProductName}
<img src= {`data:image/jpeg;base64,${product.Image2}`} width="200" height="80" />{product.Brand}
<div>
<button className="btn btn-sm btn-warning float-right"
onClick={this.addToCart}>Add to cart</button>
<div>
<input type="number" min="0" pattern="[0-9]*" onInput={this.handleInputChange.bind(this)} name={`Name${key}-${product.ProductName}-${product.Brand}`} />
</div>
</div>
</div>
</div>
))}
</div>
)
}
If by show you mean to show on screen, not inside viewCart but in separate method render()
render(){
return(
<div>
{
this.state.CartArray.map((product) => {
<p>Key: {product.Key} </p>
<p>ProductName: {product.ProductName} </p>
<p>ProductBrand: {product.ProductBrand} </p>
})
}
</div>
);
}

ReactJS: Cannot read property 'bind' of undefined

I'm tried to figure out How can I have these two buttons the Login and Sign up that will be toggling the Login and Sign up box back in forward.
I couldn't figure out.... Does anyone can solve this?
this is my code. I'd like to call "selected-controller" method from div item. But then, Cannot read property 'bind' of undefined.
Navigation.js
import React from 'react';
import { BrowserRouter as Router, Link } from 'react-router-dom';
import "../components/pages/Forms/MainScreen";
import Dropdown from "../components//pages/dropdowns/dropdowns";
import hamburger from "../images/menu.svg";
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
isExpanded: false
};
}
handleToggle(e) {
e.preventDefault();
this.setState(prevState => ({
isExpanded: !prevState.isExpanded, // negate the previous expanded state
}));
}
render() {
const { isExpanded } = this.state;
return (
<Router>
<div className="NavbarContainer">
<div className="mobilecontainer LeftNav">
<h2 className="BrandName LeftNav mobileboxmenu inline FarRight">Kommonplaces</h2>
<div className="hamburger inlinev" >
<img
onClick={e => this.handleToggle(e)}
alt="menubtn"
src={hamburger}
/>
</div>
</div>
<ul className={`NavBar collapsed ${isExpanded ? "is-expanded" : ""}`}>
<Dropdown/>
<li className="RightNav"><Link to="/">Host Your Space</Link></li>
<li className="RightNav"><Link to="/">About Us</Link></li>
<li className="RightNav"><Link to="/">Contact Us</Link></li>
<div className="btnflexright">
<div
className={"controller " + (this.state.isLoginOpen
? "selected-controller"
: "")}
onClick={this
.showLoginBox
.bind(this)}>
Login
</div>
<div
className={"controller " + (this.state.isRegisterOpen
? "selected-controller"
: "")}
onClick={this
.showRegisterBox
.bind(this)}>
Sign up
</div>
</div>
</ul>
</div>
</Router>
);
}
}
export default Navigation;
This is the main screen where the login and Sign form will go:
import React from 'react';
import RegisterBox from '../Forms/Register'
import LoginBox from '../Forms/Register'
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoginOpen: true,
isRegisterOpen: false
};
}
showLoginBox() {
this.setState({isLoginOpen: true, isRegisterOpen: false});
}
showRegisterBox() {
this.setState({isRegisterOpen: true, isLoginOpen: false});
}
render() {
return (
<div>
<div className="root-container">
{this.state.isLoginOpen && <LoginBox/>}
{this.state.isRegisterOpen && <RegisterBox/>}
</div>
</div>
)
}
}
export default App;
Login and Sign up Form are the same but in two different files Login.js and Register,js I will show the code for that one now.
//Login Box
import React from 'react';
class LoginBox extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<div className="formContent modal-main">
<h2>Welcome Back <span>Brandon!</span></h2>
<form>
<input
type="text"
name="email"
placeholder="Email Address"
/>
<input
name="password"
type="text"
placeholder="Password"
/>
<div className="passContent">
<div className="checkingPass">
<input
className="inline"
type="checkbox"
name="check"
value="Remember Password"
/>
<span
className="inline">
Remember Password
</span>
</div>
<p
className="passFont">
Forgot Password
</p>
</div>
<input
className="formmbtn"
type="button"
name="button"
alue="Login"
/>
<div
className="social-media-button">
<input
className="clearbtn"
type="button"
name="button"
value="Sign in with Facebook"
/>
<div
className="divider"
/>
<input
className="clearbtn"
type="button"
name="button"
value="Sign in with Facebook"
/>
</div>
<p
className="passFont">
Don't have an account?
<span>Sign up</span>
</p>
</form>
</div>
</div>
)
}
}
export default LoginBox;
The class Navigation doesn't have the functions showRegisterBox and showLoginBox, so this.showRegisterBox is undefined (that's why you get the Cannot read property 'bind' of undefined error when you do this.showRegisterBox.bind() on the Navigation Component.
Possible solutions:
If those functions aren't defined in the Navigation component, then you should probably pass them as props when you instantiate Navigation. That's the usual way a component communicates with it's parent component.
So if for example you were to use your Navigation component in App (which is where those functions are defined), you would do:
<Navigation showRegisterBox={this.showRegisterBox.bind(this)} showLoginBox={this.showLoginBox.bind(this)}/>
Then in Navigation you use them like such:
onClick={this.props.showRegisterBox}

Passing from child to parent from a component with 3 objects

I got a component with 2 buttons and 1 input text. The button 1 decrease a item and the button 2 increment a item to a input. I need to got the value from the input when I decrease/increment a item. The decrease/increment its working, but I can't (I don't know how) get the value in parent component.
This is my child component, named ChooseQuantity:
import React, { Component } from 'react';
import './ChooseQuantity.css';
class ChooseQuantity extends Component{
constructor(props){
super(props);
}
state = {
qtd: 0,
}
addItem(){
this.setState({qtd: this.state.qtd + 1 });
}
removeItem(){
if(this.state.qtd > 0){
this.setState({qtd: this.state.qtd - 1 });
}
}
render() {
return(
<div>
<button className="minus" onClick={() => this.removeItem()}>
<i className="fas fa-minus"></i>
</button>
<input className="qtd" type="text" value={this.state.qtd} name='qtd' onChange={this.props.action} onInput={(e) => this.setState({ choose_quantity: e.target.value })} readOnly />
<button className='plus' onClick={() => this.addItem()} >
<i className="fas fa-plus"></i>
</button>
</div>
)
}
}
export default ChooseQuantity;
This is part of my parent component, named Event (note that the child component it's in a array):
{
this.state.tickets.map((ticket, i) => (
<div key={i}>
<div className="row">
<div className="col">
<h3 className="ticket-name">{ ticket.name }</h3>
</div>
</div>
{ticket.lot.map((lot, j) =>
<div className="row" key={i}>
<div className="col-8">
<h5 className="lot-name">{ lot.name }</h5>
<h6 className="lot-price">
R$ { lot.price.replace('.', ',') } <br />
<small>(R$ { lot.price.replace('.', ',') } + R$ { lot.price_tax.replace('.', ',') })</small>
</h6>
</div>
<div className="col-4">
<ChooseQuantity />
{this.state.qtd}
</div>
</div>
)}
<hr />
</div>
)
)
}
You should 'lift up' the state in to a common parent that handles the logic and pass handlers like onAddItem, onRemoveItem and a value prop down to your buttons and input.
See here for detail on lifting state up: https://reactjs.org/docs/lifting-state-up.html

How to change the state of an item affected by onClick in array?

I'm making a page where I need to make multiple selections of buttons (like a filter, which I'll use for the next page).
the information from these buttons is coming from an array and I'm using .map () to mount the button list.
My problem is how do I change the state of only the button that was clicked. The way it is now, when I click, all the buttons are active.
How can I solve this?
Thank you.
import React from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { getLevel, getDiscipline } from '../../functions';
import template from './index.pug';
export default class ConfigAssessment extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
constructor(props){
super(props);
this.state = {
level: getLevel(),
discipline: getDiscipline(),
active: '',
first_click: true,
}
}
changeActive = () => {
if (this.state.first_click === true) {
this.setState({
active: 'active',
first_click: false
});
} else {
this.setState({
active: '',
first_click: true,
});
}
}
render() {
return(
<div className="configuration">
<div className="config-title">
<i className="ti-settings" />
<h2>
<FormattedMessage {...messages.configAssessment} />
</h2>
</div>
<div className="config-items">
<div className="form-group">
<label>
<FormattedMessage {...messages.level} />
</label>
<div className="row">
{this.state.level.map((level, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={level.id}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
id={level.id}
onClick={this.changeActive}
>
{level.level}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.discipline} />
</label>
<div className="row">
{ this.state.discipline.map((discipline, i) => (
<div className="col-xs-1 col-md-4 col-lg-3" key={i}>
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
{discipline.discipline}
</button>
</div>
))}
</div>
</div>
<div className="form-group">
<label>
<FormattedMessage {...messages.selectQuestion} />
</label>
<div className="row">
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeAutomatic} />
</button>
</div>
<div className="col-xs-1 col-md-4 col-lg-3">
<button
className={`btn btn-light-gray btn-block ${this.state.active}`}
onClick={this.changeActive}
>
<FormattedMessage {...messages.typeManual} />
</button>
</div>
</div>
</div>
<div className="form-group fg-right">
<Link className="btn btn-warning" to="#">
<FormattedMessage {...messages.createAssessment} />
</Link>
</div>
</div>
</div>
);
}
}
Create a separate component for button
class MyButton extends Component {
constructor(props){
super(props);
this.state = {
person: this.props.person
}
}
buttonActiveHandler = () => {
let oldStatus = this.props.person.status;
this.props.person.status = (!oldStatus ? 'active': '');
this.setState({
person:this.props.person
});
}
render() {
return (
<button className={this.state.person.status} onClick={this.buttonActiveHandler}>{this.state.person.name}</button>
);
}
}
export default MyButton;
Then import button component. use map function to for your code block
<div className={classes.Box}>
<h4>Lorem, ipsum.</h4>
{
this.props.survey.map((person, i) => {
return (
<MyButton key={i} person={person}/>
)
})
}
</div>
The easiest solution to this problem is making the component of the content inside the map and then handling the state of that component there. Hence it will maintain individual states.
It depends what you need.
You can create separate component for button with state.
You can also keep state of each button in react state as an array, and then you can get the state of each button by index.
I'd recommend the first solution, it'd easier to manage such state, but it will be harder to get the state of a specific button from the parent component.

Resources