I want to show and hide a form on toggle of a radio button in React js . Im trying how to use react hooks to hide or show a component on onChange even - javascript

Now i have used state hook to hide the Form when the page loads. And upon the click or toggle of the radio I'm able to show the Form, But if i toggle the radio again, the form is not hiding.
This is what i have implemented:
const WelcomeTab = () => {
const [toggle, settoggle] = useState(false);
return (
<React.Fragment>
<Tab.Pane
style={{
borderRadius: '7px',
padding: '30px',
}}
attached={false}
>
<Grid>
<Grid.Row>
<Grid.Column floated="left" width={8}>
<Header
style={{
fontSize: '18px',
fontFamily: 'Nunito-Regular',
color: '#4F4F4F',
}}
>
Welcome Screen
</Header>
</Grid.Column>
<Grid.Column floated="right" width={4}>
<Header
as="h4"
style={{
display: 'flex',
justifyContent: 'space-around',
marginLeft: '30px',
}}
>
Customize
<Radio toggle onChange={() => settoggle({ toggle: !toggle })} />
</Header>
</Grid.Column>
</Grid.Row>
</Grid>
{toggle ? (
<Form style={{ paddingTop: '20px' }}>
<Form.Field>
<label style={lableStyle}>Title</label>
<input style={{ marginBottom: '20px' }} />
<label style={lableStyle}>Message</label>
<TextArea />
</Form.Field>
</Form>
) : null}
</Tab.Pane>
</React.Fragment>
);
};
const lableStyle = {
fontFamily: 'Nunito-Regular',
fontWeight: 400,
color: '#4F4F4F',
fontSize: '15px',
display: 'inline-block',
marginBottom: '10px',
};
export default WelcomeTab;

try to add useEffect hook along with change like below,
you no longer need to {} this is old syntax of setState, using hooks we directly make the changes, hope this helps
useEffect(()=>{},[toggle])
replace this wrong syntax code, i can see its not json its boolean value
<Radio toggle onChange={()=>settoggle({toggle: !toggle})}/>
as this is old syntax not work with hooks, try to implment this instead,
<Radio toggle onChange={()=>settoggle(!toggle)}/>

Related

Skeleton-Avatar and ImageButton in MUI React are forced to oval background shapes

When using mui Stack I get weird side effect of geting all the background shapes of Skeleton Avatar and background area smeared to oval|elipsoid shapes. I tried setting equal width and height for Avatar but id does not help.
How can I fix it throguh sx mui component property or css?
code fragment
<Box
noValidate autoComplete="off"
sx={{ marginLeft: '15%','& .MuiTextField-root': { m: 2, width: '25ch' }}}>
<div>
<form onSubmit={onSubmit} >
{formFields.map((form, index) => {
return (
<Fade in={true} sx = {{width: '95%'}} {...{ timeout: 500 }}>
<Stack direction="row" borderRadius="0" spacing={2} key={index} style ={{marginLeft: '-50px', }}>
{form.img? <Avatar alt="release img" src={form.img} sx={{ width: 56, height: 56 }} /> : <Skeleton animation={false} variant ='circular'> <Avatar sx={{ width: 56, height: 56}} /> </Skeleton>}
<TextField {/* ... */}/>
<IconButton onClick={() => removeFields(index)}><DeleteIcon /</IconButton>
</Stack>
</Fade>
)
})}
</form>
<IconButton onClick={addFields} color={'warning'}> <AddCircleOutlineOutlinedIcon /></IconButton>
<br></br><br></br>
<Button onClick={onSubmit} color={'warning'} variant="contained" endIcon= {<SendIcon/>} > Search links </Button>
Normally, the default value of align-items for flex items will be stretch, that's why you see your icon is stretched in the cross axis
The solution is simple, set alignItems prop in Stack to a different value rather than normal/stretch. Here I use center
<Stack
direction="row"
borderRadius="0"
spacing={2}
alignItems="center" // this line
style={{ marginLeft: "-50px" }}
>
Demo
References
CSS align-items

card slide down in react spring not working

I am new to react and I am trying to slide down my div element using react-spring. However, the slide-down effect is not working. I saw this in a tutorial and tried to implement it however it's not working.
Here is my code:
<Spring from={{ opacity: 0, marginTop: -500 }} to={{ opacity: 1, marginTop: 0 }}>
{props => (
<div style={props}>
<div style={{ display: cost ? 'block' : 'none' }}>
<Card className="calculation shadow">
<CardBody>
<div style={{ borderTop: '2px solid #000 ', marginLeft: 20, marginRight: 20
}}></div>
<Row style={{ float: 'right', marginBottom: '1rem' }}>
<span style={{ float: 'right' }}>
<FontAwesomeIcon icon={faClipboardList} onClick={this.handler} />
</span>
</Row>
<div style={{ borderTop: '2px solid #000 ', marginLeft: 20, marginRight: 20
}}></div>
</CardBody>
</Card>
</div>
</div>
)}
</Spring>
How do I make it work so that the div component slides down when clicking a button? Please help
You're not passing the animated styles to an animated.div. Which means the props from the spring will not animate your component.
Also since you're trigger the animation on a click. I would set the animated values – opacity & marginTop as state variables. Then you on the onClick handler you can update the state triggering a change in the animation.
See the Spring docs here
And for more information, here's a codesandbox
I found the solution everything is fine no animated div required I had to just change the version of react- spring to npm i react-spring#8.0.20 and it works

Show length of an array based on what is left in array after its sliced

I have a react component that upon clicking showMore. it will load more comments. The issue im facing is that
View {showMore} More Comments
is not showing the items that are left in the array. Currently there are 7 comments in an array, and if you click show more, it will initially read show 3 more, but when i click again it says show 6 more. when it should be a lesser number than 6. It should be like show 2 more, etc. I'm quite confused on how to go about writing this logic.
What am i doing wrong
CommentList.tsx
import React, { Fragment, useState } from "react";
import Grid from "#material-ui/core/Grid";
import List from "#material-ui/core/List";
import Typography from "#material-ui/core/Typography";
import CommentItem from "./../commentItem/CommentItem";
import moment from "moment";
import OurLink from "../../../common/OurLink";
import OurSecondaryButton from "../../../common/OurSecondaryButton";
import OurModal from "../../../common/OurModal";
.....
function CommentList(props: any) {
const [showMore, setShowMore] = useState<Number>(3);
const [openModal, setOpenModal] = useState(false);
const [showLessFlag, setShowLessFlag] = useState<Boolean>(false);
const the_comments = props.comments.length;
const inc = showMore as any;
const showComments = (e) => {
e.preventDefault();
if (inc + 3 <= the_comments) {
setShowMore(inc + 3);
} else {
setShowMore(the_comments);
}
// setShowLessFlag(true);
};
........
const showMoreComments = () => {
return props.comments
.slice(0, showMore)
.sort((a, b) => a.id - b.id)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ cursor: "pointer", fontSize: "12px", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
</span>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
));
};
console.log(props.comments.slice(0, showMore).length);
return (
<Grid>
<Fragment>
<div style={{ margin: "30px 0px" }}>
<OurSecondaryButton onClick={(e) => showComments(e)} component="span" color="secondary">
View {showMore} More Comments
</OurSecondaryButton>
</div>
</Fragment>
{showLessFlag === true ? (
// will show most recent comments below
showMoreComments()
) : (
<Fragment>
{/* filter based on first comment */}
{props.comments
.filter((item, i) => item)
.sort((a, b) => b.id - a.id)
.slice(0, showMore)
.map((comment, i) => (
<div key={i}>
<List style={{ paddingBottom: "20px" }}>
<img alt="gravatar" style={{ margin: "-10px 15px" }} src={comment.author.gravatar} width="30" height="30" />
<Typography style={{ display: "inline-block", fontWeight: 700, padding: "5px 0px" }} variant="h6" align="left">
{Object.entries(props.currentUser).length === 0 ? (
<Fragment>
<span style={{ fontSize: "12px", cursor: "pointer", fontWeight: isBold(comment) }} onClick={handleClickOpen}>
{comment.author.username}
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</span>
{openModal ? <OurModal open={openModal} handleClose={handleCloseModal} /> : null}
</Fragment>
) : (
<Fragment>
<OurLink
style={{ fontSize: "12px", fontWeight: isBold(comment) }}
to={{
pathname: `/profile/${comment.author.username}`,
}}
title={comment.author.username}
/>
{comment.userId === props.userId && <span style={{ fontSize: "12px" }}> (OP)</span>}
</Fragment>
)}
</Typography>
<div style={ourStyle}>
<CommentItem comment={comment} user={props.user} postId={props.postId} {...props} />
<Typography style={{ fontSize: "12px" }} variant="body1" align="left">
{moment(comment.createdAt).calendar()}
</Typography>
</div>
</List>
</div>
))}
</Fragment>
)}
</Grid>
);
}
// prevents un-necesary re renders
export default React.memo(CommentList);
You want to show 3 more comments each time, or 1-2 items if there are less than 3 items left. So "View 3 More comments" if there are more than 3 left, or "View 1/2 More Comments" if there are only 1 or 2 left.
Or in other words cap the number of new comments shown at 3:
the minimum value of either 3 or (total number of comments - current shown comments = number of comments left).
View {Math.min(3, the_comments - inc)} More Comments

How to use Checkbox and Radio Buttons with Formik, Yup, Ui Kitten in React Native

I am using Formik and yup for forms in my app. I am not able to implement checkbox with Formik, implemented this solution but its not working with me. Below is the code I have tried so far. After implementing this solution when i click on checkbox the form become invalid and submit button does not call handleSubmit method. I also tried using React Native Elements instead of UI Kitten but result was the same.
const validationSchema = Yup.object().shape({
service_charge_status: Yup.boolean(),//.oneOf([true], 'Please check the agreement'),
documents_status: Yup.boolean(), //.oneOf([true], 'Please check the agreement'),
security_number: Yup.string()
.label('Security Number *')
.required('Security Number is required'),
note: Yup.string().label('Note')
})
handleSubmit = (values: any) => {
console.log('AD Values', values);
}
render() {
return (
<Formik
initialValues={{
// id: '',
service_charge_status: false,
documents_status: false,
security_number: '',
note: '',
security_personel_number: ''
}}
onSubmit={values => { this.handleSubmit(values) }}
validationSchema={validationSchema}
>
{({ handleChange,
values,
handleSubmit,
errors,
isValid,
isSubmitting,
touched,
handleBlur,
setFieldValue }
) => (<ScrollView>
<Header
noBackButton={true}
navigation={this.props.navigation}
title="Approve Request"
/>
<Layout style={{ padding: 20 }}>
<View style={{ marginVertical: 5 }}>
<Text category="p1" style={{ marginVertical: 5 }}>
Requester Type
</Text>
<View style={{ flexDirection: 'row' }}>
<RadioGroup
selectedIndex={this.state.requestTypeIndex}
onChange={(index) => this.setState({ requestTypeIndex: index })} >
<Radio
text="New Issue"
textStyle={styles.labelColor}
// checked={values.is_new_issue}
status="warning"
/>
<Radio
text="Replacement"
textStyle={styles.labelColor}
// checked={values.is_replacement}
// onChange={handleChange('is_replacement')}
status="warning"
/>
</RadioGroup>
</View>
</View>
<View style={{ marginVertical: 5 }}>
<Text category="p1" style={{ marginVertical: 5 }}>
Check List
</Text>
<Layout style={{ marginVertical: 6 }}>
<CheckBox
text="Service Charges"
textStyle={styles.labelColor}
status="warning"
checked={values.service_charge_status}
onChange={(val) => setFieldValue('service_charge_status', !values.service_charge_status)}
/>
</Layout>
<Layout style={{ marginVertical: 6 }}>
<CheckBox
text="Documents Verification"
textStyle={styles.labelColor}
status="warning"
checked={values.documents_status}
onChange={(val) => setFieldValue('documents_status', !values.documents_status)}
/>
</Layout>
</View>
<View style={{ marginVertical: 5 }}>
<Text category="p1" style={{ marginVertical: 5 }}>
Security Personel Number *
</Text>
<Input
placeholder="Enter Security personel number"
size='small'
multiline={true}
status={touched.security_personel_number ? !errors.security_personel_number ? 'success' : 'danger' : 'warning'}
caption={(touched.security_personel_number && errors.security_personel_number) ? errors.security_personel_number : ''}
value={values.security_personel_number}
onChangeText={handleChange('security_personel_number')}
/>
<Text category="p1" style={{ marginVertical: 5 }}>
Note *
</Text>
<Input
placeholder="Enter Note"
size='small'
multiline={true}
status={touched.note ? !errors.note ? 'success' : 'danger' : 'warning'}
caption={(touched.note && errors.note) ? errors.note : ''}
value={values.note}
onChangeText={handleChange('note')}
/>
</View>
{this.state.formSpinner &&
<View style={styles.centeredContentViewStyle}>
<ActivityIndicator animating size="small" color="#fbaf3a" />
</View>}
{this.state.error ?
<View style={styles.centeredContentViewStyle}>
<Text style={styles.errorMessageStyle}>{this.state.error}</Text>
</View> : null}
<Layout
style={{
justifyContent: 'flex-end',
flexDirection: 'row',
marginVertical: 10,
}}>
<Button
style={styles.cancelButton}
onPress={() => this.props.navigation.goBack()}>
Cancel
</Button>
<Button
style={styles.submitButton}
// type="submit"
// disabled={!isValid || this.state.formSpinner}
>
{isValid + ' Submit'}
</Button>
</Layout>
</Layout>
</ScrollView>)}
</Formik>
);
}
}
const styles = StyleSheet.create({
submitButton: {
borderColor: '#00c851',
backgroundColor: '#00c851',
marginStart: 5,
},
cancelButton: {
borderColor: '#ff3547',
backgroundColor: '#ff3547',
},
labelColor: {
color: '#8F9BB3',
},
centeredContentViewStyle: {
justifyContent: 'center',
alignItems: "center",
padding: 2,
marginVertical: 5
},
errorMessageStyle: {
color: 'red'
}
});
I'm using Formik with Chakra UI's Checkbox and ended up using the onChange event to solve this issue like so:
<Field name="terms">
{({ field }) => (
<Checkbox
id="terms"
name="terms"
onChange={(e) => setFieldValue('terms', e.target.checked)}
>
<Text fontSize="sm" textAlign="left">
I agree to the Terms and Conditions.
</Text>
</Checkbox>
)}
</Field>
I believe something similar with work with UI Kitten.
This GitHub comment was really helpful for Yup validation.
Formik expects to receive ChangeEvent as argument of handleChange function. You can do it with Input, but not with Radio or CheckBox because, in a few words, these components simulate this event by handling regular onPress from TouchableOpacity.
My solution was using hooks to handle these changes and then combining state with resulting object from Formik.
I'm using material-ui, but i believe the solution can be similar. If you have problems linking formik with any library, try to expose the form/field api and manually set the properties. When it works, try to remove some of the properties handled automatically by formik to avoid recreate the wheel.
This is how i implemented radiogroup:
<Field name="fieldName" value={formik.values.fieldName}>
{({ form }) => (
{/* Fragment is used here, to make possible to add a FormHelperText under Field. */}
<React.Fragment>
{/* Remember to use same name as in the parent Field. form.handleEvent will make it work when you click on one of the options. */}
<RadioGroup name="fieldName" onChange={form.handleChange}>
<FormControlLabel value="A" control={<Radio />} label="Value A" />
<FormControlLabel value="B" control={<Radio />} label="Value B" />
<FormControlLabel value="C" control={<Radio />} label="Value C" />
</RadioGroup>
<FormHelperText error={Boolean(form.errors.fieldName) && form.touched.fieldName}>
{form.errors.fieldName}
</FormHelperText>
</React.Fragment>
)}
</Field>
References:
Material UI
Formik Material UI
Formik Field API
Uı kits or elements don't matter. You can easily handle with formik and yup.
Add your initial values
Add your radio element to your validation schema and set your requirement like required.
Use setFieldValue or manipulate values
Then boom!

Copied code for dialog in material-ui from docs, but isn't working, what am I doing wrong?

I copied code for material-ui dialog feature for react, but couldn't figure out why this isn't working at all. Clicking the contact button doesn't even cause it to call the handleClickOpen method.
The contact button is the one that's supposed to open the dialog box, all the dialog code is copied from the docs of material-ui so I'm not sure how this couldn't be working.
export default function Banner() {
const [open, setOpen] = React.useState(false);
function handleClickOpen() {
setOpen(true);
}
function handleClose() {
setOpen(false);
}
const classes = useStyles();
return (
<Container maxWidth="lg">
<div className={classes.root}>
<Grid container spacing={7}>
<Grid item lg={6} xs={12}>
<div className={classes.title}>
<Title content="Freightage Solutions" />
<br />
<SubTitle content="A lean, modern, and efficient shipping brokerage." />
<div className={classes.buttons}>
<Button ClassName={classes.button} content="Get Started" color='white' />
<Button ClassName={classes.button} content="Contact Us" color='blue' onClick = {handleClickOpen} />
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Use Google's location service?"}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Let Google help apps determine location. This means sending anonymous location data to
Google, even when no apps are running.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Disagree
</Button>
<Button onClick={handleClose} color="primary" autoFocus>
Agree
</Button>
</DialogActions>
</Dialog>
</div>
</div>
</Grid>
<Grid item lg={6} xs={12}>
<img src={Image} className={classes.image} />
</Grid>
</Grid>
</div>
</Container>
);
}
EDIT: Here is the custom button component I'm using
import React from 'react';
import Typography from '#material-ui/core/Typography';
import { styled } from '#material-ui/styles';
import createBreakpoints from "#material-ui/core/styles/createBreakpoints";
import Button from "#material-ui/core/Button"
const breakpoints = createBreakpoints({});
const CustomButton = styled(Button)({
border: '2px solid #FFFFFF',
borderRadius: 80,
height: 48,
padding: '0 20px',
textTransform: 'none',
marginBottom: '20px',
marginRight: '30px',
marginLeft: '30px',
[breakpoints.up("lg")]: {
marginLeft: '0px',
},
});
const BlueButton = styled(CustomButton)({
background: '#0071F7',
color: 'white',
'&:hover': {
background: 'white',
color: '#0071F7',
},
});
const WhiteButton = styled(CustomButton)({
background: 'white',
color: '#0071F7',
'&:hover': {
background: '#0071F7',
color: 'white',
}
});
const ButtonType = styled(Typography)({
fontFamily: 'Ubuntu',
fontWeight: 450,
});
export default class Title extends React.Component {
render (){
if(this.props.color == 'white'){
return (
<WhiteButton gutterBottom>
<ButtonType>
{this.props.content}
</ButtonType>
</WhiteButton>
)
} else{
return(
<BlueButton gutterBottom>
<ButtonType>
{this.props.content}
</ButtonType>
</BlueButton>
)
}
}
}
It would be a good idea to use the onClick-prop you provided with to your CustomButton and set it on your button.
export default class Title extends React.Component {
render () {
if(this.props.color == 'white'){
return (
<WhiteButton onClick={this.props.onClick} gutterBottom>
<ButtonType>
{this.props.content}
</ButtonType>
</WhiteButton>
)
} else{
return(
<BlueButton onClick={this.props.onClick} gutterBottom>
<ButtonType>
{this.props.content}
</ButtonType>
</BlueButton>
)
}
}
}
As per the API Doc, there is no props called content for Button instead use children like,
<Button className={classes.button} children="Get Started" style={{color:'white'}} />
<Button className={classes.button} children="Contact Us" style={{color:'blue'}} onClick = {handleClickOpen} />
Update
You are using Button name to your custom component and material-ui also have the component with same name. As you are using both in same place there is a conflict and not a error from material-ui which one to use and your functionality is not working. This is probably the problem.
Try to change your custom button component name and check if it works.
Update 2
if(this.props.color == 'white'){
return (
<WhiteButton gutterBottom>
<ButtonType>
<Button onClick={this.props.onClick}>{this.props.content}</Button> //You forgot to use Button here
</ButtonType>
</WhiteButton>
)
} else{
return(
<BlueButton gutterBottom>
<ButtonType>
<Button onClick={this.props.onClick}>{this.props.content}</Button>
</ButtonType>
</BlueButton>
)
}
you should use proper material-ui Button API(https://material-ui.com/api/button/)
<Button children="Get Started" style={{color:'white'}} />
<Button children="Contact Us" style={{color:'blue'}} onClick = {handleClickOpen} />
check this: https://codesandbox.io/s/3fl8r

Categories