React - get value of input on click - reactjs

I'm pretty new to React. I have a simple app where text is entered into an input field and then sent to a server when a button is clicked. How can I get the value of the input field? This is incredbily easy in jQuery but I can't figure it out with React.
Here's my code:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props)
this.state = {
terms: ''
}
this.updateTerms = this.updateTerms.bind(this);
}
updateTerms(evt) {
this.setState({
terms: evt.target.value
})
}
search() {
alert(this.state.terms)
}
render() {
const btn1 = {
width: '100%',
backgroundColor: 'white'
}
return (
<div className= 'wrapper'>
<div className= 'item1'>
Specials Fact Tree Demo
</div>
<div className= 'item2'>
Search Term(s):<br/>
<input className= 'form-control' type="text" onChange={this.updateTerms} />
<br/>
<div id = 'results' >
<div id='resultsWrap' >
<select className= 'form-control' id= 'styles' ></select>
<select className= 'form-control' id= 'similar' ></select>
<div id= 'attsDiv' className= 'form-control' >
<dl id= 'atts'></dl>
</div>
</div>
</div>
<button className="btn btn-default" style = {btn1} id= 'search' onClick={this.search}>Search</button>
<div id="activeTraining" >
</div>
</div>
</div>
);
}
}
export default App;
Any help would be greatly appreciated. Plus, easy points!

You forgot to bind the search method as well (inside the constructor):
this.search = this.search.bind(this);

If you are already familar with ECMAScript 6 you can just use arrow functions and save on the bindings like:
search = () => {
alert(this.state.terms)
}

Related

React Element appearing after second button click

Im fairly new to react and im trying to build a webapp. I'm having this problem when it comes to displaying a div that contains multiple input fields, the field lesson dont show until the second time I click my create button. However it's working perfectly when I render it with this code:
Note: Im rendering TestClonereact in CourseVideoStructure
This is CourseVideoStructure.js
import React, { Component } from 'react'
import Sidenavbar from '../../Components/Sidenavbar'
import '../../Style/pagestyle/CourseVideoStructure.css'
import Footer from '../../Components/Footer'
import { Avatar } from '#material-ui/core'
import 'react-dropzone-uploader/dist/styles.css'
import EdiText from 'react-editext'
import TestClonereact from '../../Components/TestClonereact'
export default class CourseVideoStructure extends Component {
onSave = val => {
console.log('Edited Value -> ', val)
}
id = 1;
state = {
listq: [],
}
lessons(id) {
return (
<div key={id} id={`sectionlesson-${id}`}>
<div className="section-titles">
<i class="material-icons" id="iconsectionlist" type="button" >list</i>
<EdiText
type='text'
value='Lesson Title'
onSave={this.onSave}
/>
<i class="material-icons" id="iconsectiondel" type="button">smart_display</i>
<i class="material-icons" id="iconsectiondel" onClick={e => this.remove(`${id}`)} type="button" >delete</i>
</div>
<div className="testh" >
</div>
</div>
)
}
addlesson1 = () => {
const listlesson = this.state.listq;
listlesson.push(this.lessons(this.id))
this.setState({ listlesson });
this.id++;
}
remove(id) {
const newList = this.state.listq.filter(lessons => lessons.key !== id);
this.setState({
listq: newList
})
}
addsection = () => {
const list = this.state.list;
list.push(this.section(this.id))
this.setState({ list });
this.id++;
}
render() {
return (
<div>
<Sidenavbar></Sidenavbar>
<nav class="navbar navbar-expand-md navbar-white">
<a class="navbar-brand" href="#"></a>
<Avatar className="avatar" aria-controls="simple-menu" aria-haspopup="true" src="https://avatars2.githubusercontent.com/u/56764954?s=400&u=57d85794b8c753245870e2f9051b303d1188b01d&v=4" ></Avatar>
</nav>
<div className="row">
<div className="fluid-xld" id="coursevideo-structure-xld">
<div className="course-structure-form-dsp col-md-12">
<h3 className="container"> Video Course Structure</h3><br></br><br></br>
<div className="course-structure-form " id="csf1">
<div className="section-heading">
<i class="material-icons" id="iconsection">api</i>
<EdiText
type='text'
value='Section Title'
onSave={this.onSave}
/>
</div>
{
this.state.listq.map(lessons => lessons)
}
<div className="addnewlesson" onClick={e => this.addlesson1()}>
<i class="material-icons" id="iconsectionde" role="button" type="button" >add_circle</i><span>Add New Lesson</span>
</div>
</div>
</div>
<div>
<TestClonereact></TestClonereact>
</div>
</div>
</div>
<Footer></Footer>
</div>
)
}
}
However when I try to render this component in CourseVideoStructure(the code above) it doesnt render as I would like it to:
This is TestClonereact.jsx:
import React, {useEffect, useReducer} from 'react'
import '../Style/pagestyle/CourseVideoStructure.css'
import EdiText from 'react-editext'
class TestClonereact extends React.Component {
constructor(props) {
super(props);
this.state = {
listq: [],
list: []
};
}
onSave = val => {
console.log('Edited Value -> ', val)
}
id = 1;
lessons(id){
return (
<div key={id} id={`sectionlesson-${id}`}>
<div className="section-titles">
<i class="material-icons" id="iconsectionlist" type="button" >list</i>
<EdiText
type='text'
value='Lesson Title'
onSave={this.onSave}
/>
<i class="material-icons" id="iconsectiondel" type="button">smart_display</i>
<i class="material-icons" id="iconsectiondel" onClick={e => this.remove(`${id}`)} type="button" >delete</i>
</div>
<div className="testh" >
</div>
</div>
)
}
section(id){
return (
<div key={id} id={`sds-${id}`}>
<div className="course-structure-form " id="csf1">
<div className="section-heading">
<i class="material-icons" id="iconsection">api</i>
<EdiText
type='text'
value='Section Title'
onSave={this.onSave}
/>
</div>
{
this.state.listq.map(lessons => lessons)
}
<div className="addnewlesson" onClick={async () => { this.addlesson();}}>
<i class="material-icons" id="iconsectionde" role="button" type="button" >add_circle</i><span>Add New Lesson</span>
</div>
</div>
</div>
)
}
addsection = () => {
const list = this.state.list;
list.push(this.section(this.id))
this.setState({ list });
this.id++;
}
addlesson = () => {
const listlesson = this.state.listq;
listlesson.push(this.lessons(this.id))
this.setState({ listlesson });
this.id++;
}
deletelesson = () => {
const list = this.state.list;
list.splice(this.section(this.id))
this.setState({ list });
this.id--;
}
remove(id) {
const newList = this.state.listq.filter(lessons => lessons.key !== id);
this.setState({
listq: newList
})
}
render(){
return (
<div>
{
this.state.list.map(section => section)
}
<div className="add-section-button-structure">
<button class="tablink" onClick={e => this.addsection()} >Add New Section</button>
<button class="tablink" onClick={e => this.deletelesson()} >Delete Section</button>
<button class="tablink" >Preview</button>
<button class="tablink" >Submit</button>
</div>
</div>)
}
}
export default TestClonereact
So the result in images is this:
Working fine and Added Lessons 1 by 1 in the same Section:
Working Fine and able to add lessons
Problem is when I click on Add Lesson in the Second section, nothing happens but when I click on Add section again, the lesson appear in the 3rd section not the second one:
Problem image here
I've kept tryint to solve this issue with no luck. Any kind of help is much appreciated.
Forgive me for any horrible coding.

how to manage state of the check boxes displaying in multiple bootstrap cards

On calling API I got multiple JSON objects (it could be 2,3,6 or some other count) which contains the array of string with the length of more than 6000 records in each object. I need to display these records in a bootstrap card.
For example, if I got 2 JSON object then 2 cards should be displayed and each bootstrap card contains the records' name with the checkboxes.
So, how can I manage the state of these checkboxes let say if I click on cardb apply button then only cardb checked checkboxes and the name of the card i.e., "cardb" should be captured somewhere so that I can use this info for further API calling.
Can someone please help me out in this?
Main.JSX
render() {
return (
<main
role="main"
className="flex-shrink-0">
<div className="container">
<form onSubmit={this.handleWidgetsCardFormSubmit}>
<div className="row flex-row flex-nowrap wc-main-div-scroll">
{this.displayWidgetsCard()}
</div>
</form>
</div>
</main>
);
}
displayWidgetsCard() {
if (this.state.displayWidgetsCard === true) {
console.log("Total widgets card to show: ",this.state.cardCount.length);
let t = [];
for (let i = 0; i < this.state.cardCount.length; i++) {
t.push(
<Card
key={this.state.cardCount[i].cardname}
cardName={this.state.cardCount[i].cardname}
recordCount={this.state.cardCount[i].count}
createCheckboxes={this.createCheckboxes3(this.state.cardCount[i].recordsArr)}
/>
);
}
return t;
} else {
return null;
}
}
componentWillMount = () => {
this.selectedCheckboxes3 = new Set();
};
toggleCheckbox3 = label => {
if (this.selectedCheckboxes3.has(label)) {
this.selectedCheckboxes3.delete(label);
} else {
this.selectedCheckboxes3.add(label);
}
};
createCheckbox3 = label => (
<Checkbox
label={label}
handleCheckboxChange={this.toggleCheckbox3}
key={label}
/>
);
createCheckboxes3 = array1 => array1.map(this.createCheckbox3);
Card.JSX
import React, { Component } from "react";
import "./styles.css";
class Card extends Component {
render() {
const { cardName, createCheckboxes, recordCount } = this.props;
return (
<div className="col-4">
<div className="card wc-dim border-dark sh">
<div className="card-header">
<b>
{cardName}
{" (" + recordCount + ")"}
</b>
<div className="input-group mt-2">
<input
type="text"
className="form-control search-form"
placeholder="Search"
/>
</div>
</div>
<div className="card-body wc-scroll">
<div className="card-text">{createCheckboxes}</div>
</div>
<div className="card-footer bg-transparent">
<button className="btn btn-primary" type="submit" id="btn-right">
Apply
</button>
</div>
</div>
</div>
);
}
}
export default Card;

How to use Tooltip in react-redux

I am new to react.
I want to have a tool tip on the label
The following serves my request
<div class="sds_sp_2xl sds-cb_font--primary">
To see Tooltip positioned on the right,
<a role="button" tabindex="0" aria-describedby="tooltip-cb-02" class="sds-cb_tooltip">
hover over me.
<div role="tooltip" class="sds-cb_tooltip__content sds-cb_tooltip__content--right" id="tooltip-cb-02">Contextual helper text</div>
</a>
</div>
I want to have the tooltip when we hover on the label pertained to checkbox
form
<Field
name='checkMe'
label='check'
component={Checkbox}
checked={checkMe}
{...this.checkboxActions}
/>
checkbox
export const Checkbox = (inputProps) => {
const { input, label, checked } = inputProps
const { name } = input
const className = 'sds-cb_checkbox-a__input'
return (
<label className='sds-cb_checkbox-a' >
<input {...input} className={className} checked={checked} type='checkbox' />
<div className='sds-cb_checkbox-a__box' id={name} />
<span className='sds-cb_checkbox-a__label sds_font-size--14'>{label}</span>
</label>
)
}
How do I embed it to work. So that it would be useful for the fields as well ? Thanks in advance!
Refrence of React-tooltip
This will surely help you.
class Tooltip extends React.Component {
constructor(props) {
super(props)
this.state = {
displayTooltip: false
}
}
hideTooltip=()=>{
this.setState({displayTooltip: false})
}
showTooltip=()=>{
this.setState({displayTooltip: true})
}
render() {
let message = this.props.message
let position = this.props.position
return (
<span className='tooltip'
onMouseLeave={this.hideTooltip}
>
{this.state.displayTooltip &&
<div className={`tooltip-bubble tooltip-${position}`}>
<div className='tooltip-message'>{message}</div>
</div>
}
<span
className='tooltip-trigger'
onMouseOver={this.showTooltip}
>
{this.props.children}
</span>
</span>
)
}
}
class App extends React.Component {
render() {
return (
<div className='container'>
<p>Here is a <Tooltip message={'Hello, I am a super cool
tooltip'} position={'top'}>tooltip</Tooltip> on top.</p>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
)
First off you should not wrap the label around the input element but set the for attribute to the correct id of the input. So when clicking the label the input gets focused. And to show a tooltip or start any other action use the standard javascript events onMouseEnter and onMouseLeave, set some state according to this and use this state as conditional rendering of the tooltip element:
<label for="someId" onMouseEnter={()=>this.setState({showTooltip:true})} onMouseLeave={()=>this.setState({showTooltip:false})}>Labeltext</label>
<input id="someId" .../>
{this.state.showTooltip && <div>Tooltip</div>}
This will also work when you're setting and using some redux state.

react render --How to render 2 props with map function in discussion app

having trouble with dicussion app. I can render only header or post at a given time.Having trouble how to render in thread.jsx.
This app is in react and firebase.
Pls suggest me how to fix this.
I think map function in post is not right.how to write a object with map function. do I need to write object as a prop?
thread.jsx--------
postEditor.jsx-----
import React, {Component} from 'react';
import './DpostEditor.css';
export default class PostEditor extends Component {
constructor(props) {
super(props);
this.state= {
newPostBody:'',
newHeaderBody:'',
};
this. handlePostHeaderInputChange=this.handlePostHeaderInputChange.bind(this);
this.handlePostEditorInputChange = this.handlePostEditorInputChange.bind(this);
this.createPost = this.createPost.bind(this);
}
handlePostEditorInputChange(e) {
this.setState({
newPostBody : e.target.value,
})
}
handlePostHeaderInputChange(e) {
this.setState({
newHeaderBody : e.target.value,
})
}
createPost() {
this.props.addPost(this.state.newPostBody);
this.setState({
newPostBody: '',
newHeaderBody:'',
});
}
render() {
return(
<div className= "panel panel-default post-editor">
<div className="panel-body">
<textarea className= "form-control post-header-input" value={this.state.newHeaderBody} onChange={this. handlePostHeaderInputChange }/>
<textarea className= "form-control post-editor-input" value={this.state.newPostBody} onChange={this.handlePostEditorInputChange }/>
<button className= "btn btn-success post-editor-button" onClick= {this.createPost}> Post </button>
</div>
</div>
)
}
}
Post.jsx------
import React from 'react';
import './Dpost.css';
const Post= (props)=> (
<div className=" panel panel-default post-body">
<div className="panel-heading">
{props.postBody.map((header,postType,idx)=>(
<div>
<div> {header} </div>
<div> {postType} </div>
</div>
))
}
</div>
</div>
);
export default Post;
Exactly the map function is wrong. You're passing 3 parameters that don't match the ones the map array helper uses.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Scroll to the Parameters section to check them. Right now you're passing the parameters of the post and not the array.
Perhaps you should try something like this:
{props.postBody.map((post)=>(
<div key={post.idx}>// remember the key in a map iterator
<div> {post.header} </div>
<div> {post.postType} </div>
</div>
))}
But this depends on the structure of your props.postBody array. The code above assumes that is a collection of posts.
Edit
Considering the fact that your props may be undefined at some point you use a conditional logic to run the array map helper:
{props.postBody ? props.postBody.map((post)=>(
<div key={post.idx}>// remember the key in a map iterator
<div> {post.header} </div>
<div> {post.postType} </div>
</div>
)) : null}

How to push values into state by calling single onChange function - react

I am new to reactive. I am working on react+flux+alt with ES6.
I have a form for creating new record.
Component
import React from 'react';
import { Input, Button, Glyphicon, ButtonToolbar } from 'react-bootstrap';
import AttributeSectionStore from 'stores/attributeSection/AttributeSectionStore';
import TextBoxesSet from '../descriptionTextBoxes';
import styles from 'scss/_common';
export default class AttributeSection extends React.Component {
constructor(props) {
super(props);
}
_onCreate = () => {
console.log('___________', this.state);
}
onChangeName = (evt) => {
this.setState({name: evt.target.value});
};
onChangeRank = (evt) => {
this.setState({rank: evt.target.value});
};
static getPropsFromStores() {
return recordStore.getState();
}
render() {
return (
<div className="container">
<div className={styles.mainheader}>
<h2 >New Record</h2>
</div>
<div className="col-md-9">
<form className="form-horizontal">
<div className="row">
<div className="col-md-12">
<Input type="text" label="Name" labelClassName="col-xs-2"
wrapperClassName="col-xs-4" value={this.props.name}
onChange={this.onChangeName}/>
</div>
</div>
<div className="row">
<div className="col-md-12">
<Input type="number" label="Rank" labelClassName="col-xs-2"
wrapperClassName="col-xs-4" value={this.props.rank}
onChange={this.onChangeRank}/>
</div>
</div>
<div className="row">
<div className="col-md-4 col-md-offset-2">
<ButtonToolbar className={styles.formBtnGrp}>
<Button bsStyle="primary" onClick={this._onCreate}>Create</Button>
<Button type="reset">Cancel</Button>
</ButtonToolbar>
</div>
</div>
</form>
</div>
</div>
);
}
}
AttributeSection.propTypes = {
name: React.PropTypes.string
rank: React.PropTypes.number
};
Using above component now I'm getting data into state but form may have more than 2 fields. I'm using two functions to update state instead of that how can use single function to update state object?Is there any other best practice is there?
The most common pattern to solve this is using bind() to curry a value to the onchange callback. This is was #knowbody referenced (React.js: Identifying different inputs with one onChange handler)
An alternate, but similar, pattern is adding a second tag within the element to identify the name of the state property to change. I'll show an example using label from your code (obviously you want to use a dedicated tag since label is for display and would be localized).
onInputChanged(evt) {
var newState = this.state,
propName = evt.target.label.toLowerCase();
newState[propName] = evt.target.value;
this.setState(newState);
};

Resources