I want to show the input field on toggling. The toggling is working but it is not showing the input field. How can I achieve this? I've tried but that is not showing the input field.
Here's the code:
handleToggle=()=>{
console.log('In handletoggle')
this.setState({
milestone_based_payment:!this.state.milestone_based_payment
})
}
percentRate=()=>{
<>
<div className="percent-rate-container">
<Grid container>
<Grid item md={12} lg={12} xs={12}>
<div className="percent-rate">PERCENT RATE</div>
<div>
<InputBase
className={`milestone-percent-rate`}
autoComplete={"off"}
placeholder={"PERCENT RATE"}
maxLength="100"
value={this.state.percent_rate}
onChange={(e)=>{this.handleChange(e, "percent_rate")}}
/>
{
this.state.percent_rate_error && (
<div className="input-error-style">{this.state.percent_rate_error}</div>
)
}
</div>
</Grid>
</Grid>
</div>
</>
}
togglePayment=()=>{
const {milestone_based_payment} = this.state;
console.log('togglepayment')
return(
<div>
<img src={milestone_based_payment ? PRIVATE_SwITCH : PUBLIC_SwITCH} alt="private-public"
onClick={()=>this.handleToggle()}
style={{cursor: "pointer"}}/>
</div>
);
}
You can show/hide input field on true / false condition like this:
showHideInput() {
if(this.state.milestone_based_payment === true) {
return <input />
}
}
// and call the method in other method
// or inline condition
(this.state.milestone_based_payment === true) ? <input /> : <React.Fragment />
Related
I want a component to behave exactly like Accordion.
I have managed to do that.
But I am facing one issue.
If one question is open and a user tries to open the other question,it closes the first question.
I do not want that.
I want both of them to remain open and it should be closed if a user clicks on the question again.
Here is the code -->
class Accordion extends React.Component {
constructor() {
super();
this.state = {
answer: false,
selectedQue: null,
};
}
toggleAnswer = (index) => {
const { answer } = this.state;
this.setState({
selectedQue: index,
answer: !answer,
});
};
render() {
const { answer, selectedQue } = this.state;
return (
<Row className="m-t-10">
<Col md={12} sm={12} xs={12}>
{map(
questionAnswer,
(item, index) =>
item && (
<div key={index} onClick={() => this.toggleAnswer(index)}>
<div className="d-flex justify-content-between">
<Label
header={item.key}
color={index === selectedQue && answer ? '#406AE8' : '#415070'}
/>
<span className="float-right">
<Icons
className={cx(
'vertical-align-middle',
index === selectedQue && answer
? 'ac-icon-arrow-up-xs'
: 'ac-icon-arrow-down-xs',
)}
/>
</span>
</div>
{index === selectedQue && answer && (
<div>
<span
dangerouslySetInnerHTML={{
__html: item.value,
}}
/>
</div>
)}
<hr />
</div>
),
)}
</Col>
</Row>
)
}
}
I am trying to set the error message but as in the state I've passed initial Values object, I'm unable to set the state. How can I achieve this in react? How can I set the error messages in the set State function? Can someone help me?. After console logging it is showing the error in the console. But how can I show this on screen? Thanks in advance.
Here's the code :
const initialValues={
deliverable_name:"",
due_date:new Date(),
deliverable_notes:"",
milestone_based_payment:false,
deliverable_name_error:"",
due_date_error:"",
deliverable_notes_error:""
}
class MileStoneForm extends Component {
constructor(props){
super(props)
this.state={
initialValues
}
}
handleChange=(e,type)=>{
let error=true
if(type==='deliverable_notes'){
if(e.target.value.length>300){
error=false
this.setState({deliverable_notes_error:'Description must contain less than 300 characters'})
}
}
if(error){
this.setState({
[type]:e.target.value,
[type+"_error"]: ""
})
}
}
validateMileStoneName=()=>{
if(!this.state.initialValues.deliverable_name || this.state.initialValues.deliverable_name.length< 4 ){
console.log("enter deliverable name")
this.setState({deliverable_name_error:'Please enter deliverable name'})
}
}
validateMileStoneDueDate=()=>{
if(!this.state.initialValues.due_date){
this.setState({due_date_error:'Please enter due date'})
}
}
validateMileStoneDescription=()=>{
if(!this.state.initialValues.deliverable_notes){
this.setState({deliverable_notes_error:'Please enter description'})
}
}
handleSubmit=(data)=>{
this.validateMileStoneName()
this.validateMileStoneDescription()
console.log(data)
this.props.handleData(data)
}
render() {
const {initialValues}=this.state
return (
<>
<div className="milestone">
<div className="milestone-header">ADD MILESTONE</div>
<Grid container className="milestone-deliverable-name-date">
<Grid item md={6} lg={6} xs={12}>
<div className="milestone-deliverable-name">DELIVERABLE NAME</div>
<div>
<InputBase
className={`milestone-input-deliverable-name`}
autoComplete={"off"}
placeholder={"MileStone Name"}
onChange={e=>this.handleChange(e,'initialValues.deliverable_name')}
value={initialValues.deliverable_name}
maxLength="100"
autoFocus={true}/>
{initialValues.deliverable_name_error && (
<div className="input-error-style">{initialValues.deliverable_name_error}</div>
)}
</div>
</Grid>
<Grid item md={6} lg={6} xs={12}>
<div>
<div className="milestone-due-date">
DUE DATE
</div>
<InputBase
className={`create-project-due-date`}
autoComplete={"off"}
type="date"
placeholder={"DUE DATE"}
onChange={e=>this.handleChange(e,'due_date')}
value={initialValues.due_date}/>
{initialValues.due_date_error && (
<div className="input-error-style">{initialValues.due_date_error}</div>
)}
</div>
</Grid>
</Grid>
<Grid container className="milestone-deliverable-notes">
<Grid item md={12} lg={12} xs={12}>
<div className="milestone-notes-description">
<div className="milestone-deliverable-notes">DELIVERABLE NOTES</div>
<div className="milestone-description-notes">Add description below</div>
<TextareaAutosize className={`milestone-textarea-description`}
onChange={(e)=>this.handleChange(e,'deliverable_notes')}
value={initialValues.deliverable_notes}/>
{initialValues.deliverable_notes_error && (
<div className="input-error-style">{initialValues.deliverable_notes_error}</div>
)}
</div>
</Grid>
</Grid>
<div className={initialValues.milestone_based_payment?"milestone-button":"milestone-button-margin-high"}>
<Grid container spacing={10}>
<Grid item xs={12} sm={12} md={4} lg={4}></Grid>
<Grid item xs={12} sm={12} md={4} lg={4}></Grid>
<Grid item xs={12} sm={12} md={4} lg={4}>
<div className="milestone-button-margin-btm">
<NormalButton
buttonValue="ADD"
className="btn-create-project flex-justify"
icon_color="black"
handleButtonAction={()=>this.handleSubmit(initialValues)}
/>
</div>
</Grid>
</Grid>
</div>
</div>
</>
)
}
}
export default MileStoneForm
You're mixing initialValue in the state which is an object, with the properties you're setting. So after an error, your state is actually looking like this:
this.state = {
initialValue: [object] // this could potentially mutate (a bug).
deliverable_notes_error: "Please set ....",
}
What you need to do is use the spread syntax to set your initial state:
constructor(props) {
this.state = {
...initialValues // your state is now a soft clone of the object
};
}
render(props) {
const { deliverable_notes_error } = this.state;
return (
{ deliverable_notes_error && <div>{ deliverable_notes_error }</div> }
);
}
3 things
I would move the error messages inside State.
deliverable_name_error:"",
due_date_error:"",
deliverable_notes_error:""
Update this.setState - already done
Display error messages - also doing.
Basically, if you move everything from initialValues into state, your code should work.
I'm writing a code to implement a vertical Collapse by using react material UI. But it won't set the Input and TextField values into the state variables. Please help me to find what i did wrong here. Thanks in advance.
Here is the function that is used to handle input changes
handleOnChange = async (event) => {
const field = event.target.name;
if (field === "Announcement") {
if (this.isMount) {
await this.setState({
announcement: event.target.value,
isFormDirty: true,
});
}
}
if (field === "Title") {
if (this.isMount) {
await this.setState({
title: event.target.value,
isFormDirty: true,
});
}
}
};
Part of my render() function
<form>
<div>
<ListItem button onClick={this.handleClickAnnouncement}>
<ListItemAvatar>
<Avatar>
<NotificationImportant/>
</Avatar>
</ListItemAvatar>
<ListItemText primary="Announcements"/>
{this.state.ListAnnouncementOpen === true ? <ExpandMore/> : <ExpandLess/>}
</ListItem>
<Collapse in={this.state.ListAnnouncementOpen} timeout="auto" unmountOnExit>
<div className="row" className = "ml-3" >
<label htmlFor="" className="mandatory">
Title :
</label>
<Input
placeholder="Title"
value={this.state.title}
name="Title"
onChange={this.handleOnChange}
required={true}
/>
</div>
<div className="row ml-3">
<TextField
id="standard-multiline-flexible"
label="Type new Announcement here"
onChange={this.handleOnChange}
className="course-detail-section"
name="Announcement"
required={true}
value={this.state.announcement}
/>
<Avatar onClick={this.addAnnouncement}>
<AddIcon/>
</Avatar>
</div>
</Collapse>
</div>
</form>
I'm working through some React tutorials and trying to figure out how to filter buttons out of a button group by searching for a term. My filter function works for text but I can't figure out how to get it to work with buttons.
<div className="searchbar">
<form>
<input type="text" placeholder="Search..." onChange={this.searchHandler} />
</form>
{
this.state.drinks.filter(searchingFor(this.state.term)).map(drink =>
<div key={ drink.id } >
{ drink.title }
</div>)
}
</div>
I am able to filter text with this (drink.title) but I want to filter the buttons in the section below. Is this possible with what I currently have? Sorry if this is a vague question, I'm brand new to React and would appreciate any help.
<Grid.Column className="left-col" width="3">
<Container >
<Menu >
{drinks && drinks.length
? <Button.Group vertical widths={drinks.length} >
{Object.keys(drinks).map((key) => {
return <Button size="large" fluid active={drink && drink.id === drinks[key].id} key={key} onClick={()=>this.getDrink(drinks[key].id)}>
{drinks[key].title}
</Button>
})}
</Button.Group>
: <Container textAlign='center'>No drinks found.
</Container>
}
</Menu>
</Container>
</Grid.Column>
and the search function
function searchingFor(term) {
return function(x) {
return x.title.toLowerCase().includes(term.toLowerCase()) || !term
}
}
Hello I am trying to build a forum site. I have simple categories and comments. I have a button that displays a text box to enter a comment on a category, but when I click the button it opens text boxes on every category. I just want one text box. Here is the code I have so far. Any help would be appreciated. Thanks
state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
onClick={() => this.setState({ showing: !showing })}
>
Add Comment
</button>
{showing ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}
Since you are controlling render of the form with a single state value, ever form for every item renders the form when the state value changes.
You should set a unique value on state to show single form every time.
Saving currently active items id to state and checking if that item is active or not can be a simple solution. This also ensures to only single form to be active. If you need to enable multiple forms to be active, you can change below code to hold an array of ids and checking if the id exist in array or not. This implementation also requires you to remove the id from array on a second click to remove form for that item.
Sample
state = { showing: ''};
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
{/* Save item's id to state */}
onClick={() => this.setState({ showing: category._id })}
>
Add Comment
</button>
{/* check item's id */}
{(showing === category._id) ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
You can set the dynamic state for each of your category. I have made it below. Initially it was not there in state. On clicking the button, it will update the state with new key(such as categoryName) as true. I have fixed it as toggle. If the required key is true then it will become false.
item.state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
let categoryName = category.name // get the categoryName in variable
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
//You can also access the object values by using bracket ([]) notation. You can set the dynamic state with unique key, may be we use name as key here
<button
className="label"
onClick={() => {(this.state[categoryName] != undefined) ? (this.state[categoryName] ? this.setState({ [categoryName]: false }) : this.setState({ [categoryName]: true })) : this.setState({ [categoryName]: true })} }
>
Add Comment
</button>
{this.state[categoryName] ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}