Checkbox.Group of ant design React couldn't set the default value - reactjs

I am developing an ant-design based react functional application. While using the Checkbox.Group, I found that I can't set the default value on a dynamically generated list of select boxes. My criteria is, when the custom modal is opened, depending on the loginId(an integer value) passed, the checkbox should be selected by default. If I unselect then it's fine. But on opening modal for the first time, default value should be set. I'm really trying for a long time, don't know what exactly I'm missing. Would be great if you please help.
here is my code,
export const ContactModal = props => {
const loggedInUser = props.loginUserDetail.id > 0 ? [props.loginUserDetail.id] : [];
console.log("loggedInUser= ",loggedInUser);
const title =
props.contactType === contactTypesEnum[1] ? 'Select MMS contact person' : 'Select Industry contact person';
return (
<Modal
title={title}
visible={props.isVisible}
width={'60%'}
afterClose={props.modalClose}
onCancel={props.handleContactModalCancel}
footer={[
<Button key="back" onClick={props.handleContactModalCancel}>
Cancel
</Button>,
<Button key="submit" type="primary" onClick={props.contactModalConfirm}>
{/*<Button key="submit" type="primary" onClick={props.inputSubmit}>*/}
Submit
</Button>
]}
>
{/*<Form key={props.contactList}>*/}
<Form>
<div style={{ overflowY: 'scroll' }}>
{/*<Checkbox.Group defaultValue={[defaultValue]} onChange={props.handleCheckedInput}>*/}
<Checkbox.Group defaultValue={loggedInUser} onChange={props.handleCheckedInput}>
<Row style={{ border: '1px solid #009FE3', paddingLeft: '10px' }}>
{props.contactList.map((elem: { fullName: string; id: number }, index: number) => {
return (
<Col key={index} span={8}>
<Form.Item>
<Checkbox value={elem.id}>{elem.fullName}</Checkbox>
</Form.Item>
</Col>
);
})}
</Row>
</Checkbox.Group>
</div>
</Form>
</Modal>
);
};
The props.loginUserDetail, I'm passing looks like,
export interface ContactLogin {
id:number;
fullName:string;
}
and I checked very correctly that the id is getting populated and has non-zero positive value. Strangely if I hardcode defaultValue={[12]} the right checkbox is marked but the variable assignment of defaultValue={[loggedInUser]}
In the ant design specification I found that the defaultValue type should be string so I tried to use,
const loggedInUser = props.loginUserDetail.id > 0 ? props.loginUserDetail.id.toString() : '';
But it is also not working. If variable value is not selectable then defaultValue={[12]} shouldn't work too. BUt hard-coding is working.
THis is how I'm calling the custom modal,
this is how I'm calling the modal ,
<ContactModal
isVisible={modalVisibilty}
//modalClose={modalClose}
contactList={contactList} //this would be number of contact returned
handleContactModalCancel={handleContactModalCancel}
contactModalConfirm={contactModalConfirm}
handleCheckedInput={handleCheckedInput}
//contactListError={contactListError}
contactType={contactType}
loginUserId={contactType === contactTypesEnum[2]?loginUserDetail.id:0}
//loginUserDetail={contactType === contactTypesEnum[2] ?loginUserDetail : {id:0,fullName:''}}
/>
Can anyone please help me out here ? Thanks much !

Related

Setting Active State on mapped component

I have a mapped component which iterates through API data. It passes props to each one and therefore each card looks different. See example below.
https://gyazo.com/39b8bdc4842e5b45a8ccc3f7ef3490b0
With the following, I would like to achieve two goals:
When the component is selected, it uses state to STAY SELECTED, and changes the colour as such to lets say blue for that selected component.
I hope this makes sense. How do I index a list as such and ensure the colour and state remains active based on this selection?
See below.
The level above, I map the following cards using these props.
{
jobs.length > 0 &&
jobs.map(
(job) =>
<JobCard key={job.id} job={job}
/>)
}
I am then using the following code for my components:
const JobCard = ({ job }) => {
const responseAdjusted = job.category.label
const responseArray = responseAdjusted.split(" ")[0]
return (
<CardContainer>
<CardPrimary>
<CardHeader>
<CardHeaderTopRow>
<Typography variant = "cardheader1">
{job.title}
</Typography>
<HeartDiv>
<IconButton color={open ? "error" : "buttoncol"} sx={{ boxShadow: 3}} fontSize ="2px" size="small" fontSize="inherit">
<FavoriteIcon fontSize="inherit"
onClick={()=> setOpen(prevOpen => !prevOpen)}/>
</IconButton>
</HeartDiv>
</CardHeaderTopRow>
<Typography variant = "subtitle4" color="text.secondary">
{job.company.display_name}
</Typography>
</CardHeader>
<CardSecondary>
</CardSecondary>
</CardPrimary>
</CardContainer>
)
}
export default JobCard
My suggestion is to use a state in the wrapping component that keeps track of the current open JobCard.
const [openCard, setOpenCard] = useState()
and then pass this down to job card together with a function to update.
jobs.map(
(job) =>
<JobCard
key={job.id}
job={job}
isSelected={openCard === job.id}
onSelectCard={() => setOpenCard(job.Id)}
/>)
So now you can format your JobCard differently depending on isSelected, and run onSelectCard when the card is pressed.

Fix date picker inside modal window in react js

I have this component:
const App = () => {
const [isModalVisible, setIsModalVisible] = useState(false);
const showModal = () => {
setIsModalVisible(true);
};
const handleOk = () => {
setIsModalVisible(false);
};
const handleCancel = () => {
setIsModalVisible(false);
};
return (
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
</Modal>
</>
);
};
When i open the modal i get the calendar outside it. How to put the calendar inside the modal window, not outside like now?
demo: https://codesandbox.io/s/basic-antd494-forked-6lkqg?file=/index.js:269-1303
This is, IMO, incredibly hackish, but was the only way I could get the date picker's popup to behave a bit more nicely nested in a modal.
Use the getPopupContainer prop to specify what the parent should be, it defaults to "body". We can create our own element to append the date popup to.
Use the popupStyle prop to override and set the position CSS rule. It is position: absolute by default, we wan't relative positioning.
Add an empty div after DatePicker for the popup to attach to.
HACK ALERT: DatePicker inserts a div between the one we created and the popup, so CSS rule cascading & inheritance gets fubar'd, it has position: absolute as well. We need to override this to also use relative positioning.
Code:
<>
<Button type="primary" onClick={showModal}>
Open Modal
</Button>
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
>
<DatePicker
getPopupContainer={() => document.getElementById("date-popup")}
popupStyle={{
position: "relative"
}}
onChange={test}
open={true}
showNow={false}
dateRender={(current) => {
const style = {};
if (arr.includes(current)) {
style.border = "1px solid red";
style.borderRadius = "50%";
}
return (
<div className="ant-picker-cell-inner" style={style}>
{current.date()}
</div>
);
}}
/>
<div id="date-popup" />
</Modal>
</>
CSS
#date-popup > div {
position: relative !important;
}
The main reason this is hackish is because the use of !important should generally be avoided and instead you should strive to increase a selector's specificity. I was unable to bump it enough to override the style. (I believe this is because that div is also using some inline style prop/attribute)
DatePicker itself is also a kind of Modal so it can't be embedded inside Modal. You can simply check this by inspecting both Modal and DatePicker components.
If you want the DatePicker to be opened, you can control the height of modal body. Something like this.
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
bodyStyle={{
height: 400
}}
>
Here is another suggestion:
<Modal
title="Basic Modal"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
centered
style={{ minHeight: `500px` }}
>

Why does my table component filter crash the browser tab?

I have a page with a table which is working quite fine and is very performant as it should be. I'm now trying to implement a filter for it so the users can easily check only what they need. But one weird thing is happening. If I have the filter component commented out, everything works fine. If I include it in the component it should be, the browser becomes extremely slow and even crashes my chrome tab. I was trying to comment out all the code in that component to check where the problem is but I can't figure it out.
My weird component code without the comments:
import { Grid, LuxButton } from 'luxclusif-material';
import React, { useState } from 'react';
import { FilterComponentStyles } from './FilterComponent.styles';
export default function FilterComponent() {
const classes = FilterComponentStyles();
const [status, setStatus] = useState('Supplier');
return (
<>
<div className={classes.spacing}>
{/* commented out stuff */}
</div>
<div className={`${classes.statusMenu} ${classes.spacing}`}>
<Grid
container
direction="row"
justify="flex-start"
alignItems="center"
className={classes.heightStatus}>
<div className={classes.rightMargin}>
<LuxButton
variant="contained"
luxColor={(status === 'Supplier' ? 'secondary' : 'default')}
onClick={() => setStatus('Supplier')}
className={classes.transformTextNone}
disableElevation>
<span className={classes.addButtonText}>Supplier</span>
</LuxButton>
</div>
<div className={classes.rightMargin}>
<LuxButton
variant="contained"
luxColor={(status === 'Active' ? 'secondary' : 'default')}
onClick={() => setStatus('Active')}
className={classes.transformTextNone}
disableElevation>
<span className={classes.addButtonText}>Active</span>
</LuxButton>
</div>
<div className={classes.rightMargin}>
<LuxButton
variant="contained"
luxColor={(status === 'Inactive' ? 'secondary' : 'default')}
onClick={() => setStatus('Inactive')}
className={classes.transformTextNone}
disableElevation>
<span className={classes.addButtonText}>Inactive</span>
</LuxButton>
</div>
</Grid>
</div>
</>
);
}
This FilterComponent is being called like this:
<TableContainer component={Paper} >
<FilterComponent ></FilterComponent>
<Table>
{/* table code */}
</Table>
</TableContainer>
Notes: LuxButton is an extension of material-ui Button and its luxColor property is the extension to the color property.

How do I update state to specific value?

I hope you're all well.
I would be so grateful if any of you can shed some light on the following question..
There are two relevant components:
Parent component which fetches data using GraphQL
let authors = "";
const { loading, data } = useQuery(FETCH_AUTHORS_QUERY);
console.log(`Loading: ${loading}`);
//console.log(data);
if (data) {
authors = { data: data.getAuthors };
}
return (
<Grid columns={3}>
<Grid.Row className="page-title">
<h1>Recent Essays</h1>
</Grid.Row>
{loading ? (
<h1>Loading essays..</h1>
) : (
authors.data &&
authors.data.map(author => (
<Grid.Column key={author.id} style={{ marginBottom: 20 }}>
<AuthorCard author={author} />
</Grid.Column>
))
)}
<Grid.Row></Grid.Row>
</Grid>
);
}
const FETCH_AUTHORS_QUERY = gql`
{
getAuthors {
id
Author
Description_1
Description_2
}
}
`
Child component called 'AuthorCard' (you can see placed in the parent component above):
function AuthorCard({ author: { Author, Description_1, id } }) {
const [writer, setWriter] = useState();
return (
<Card fluid>
<Card.Content>
<Image
floated="right"
size="mini"
src="https://image.cnbcfm.com/api/v1/image/105691887-1556634687926ray.jpg?v=1576249072"
/>
<Card.Header>{Author}</Card.Header>
<Card.Meta as={Link} to={`/essays`}></Card.Meta>
<Card.Description>{Description_1}</Card.Description>
</Card.Content>
<Card.Content extra>
<Button as="div" labelPosition="right">
<Button color="teal" basic>
<Icon name="heart" />
</Button>
<Label basic color="teal" pointing="left"></Label>
</Button>
<Button labelPosition="right" as={Link} to={`/essays`}>
<Button
color="blue"
basic
key={Author.id}
onClick={() => setWriter(Author)}
>
<Icon name="comments" />
</Button>
</Button>
</Card.Content>
</Card>
);
}
export default AuthorCard;
The issue is as follows:
When I click the as={Link} to={/essays} button in the child component, I would like to 'setWriter' state to the individual Author whose button I am clicking on.
However, I am not able to specify the individual author whose button is being clicked on. React thinks I want to 'setWriter' for the entire list of authors. For example, when I console.log(Author) within the button, I can see every author in the list printed in the console.
I have tried adding id, using event.target .value, and onChange instead of onClick.
I just haven't been able to target the individual author in order to update the state (which will be needed in a different component).
Please let me know if anything isn't clear or if it would be helpful to provide more details.
Thanks in advance and happy coding!!!
Dan
You should use a destructuring assignment expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
I think you should declare your child component like this:
function AuthorCard({ Author, Description_1, id }) {
...
...
...
}
Thanks for the reply.
I finally solved the issue. I had to use:
onClick={e => setWriter(e.currentTarget.Author)}
I hadn't known about using 'current target.'
I can then transfer the state to other components through useContext.
Hopefully this can help someone else!
Dan

How can I reduce the number of buttons?

I need to have only one button doing two things one by one. I have two buttons "Обучить" and "Генерировать" and they both do something onClick. Is it possible to do it all with one button?
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={this.parseInput}
>
Обучить
</Button>
<Button
variant="contained"
color="primary"
style={{
background:
"linear-gradient(45deg, #00ACD3 30%, #00BE68 90%)"
}}
onClick={() => {
this.props.updateData(this.state.filterArray);
}}
>
Генерировать
</Button>
Of course you can. You can use a variable to decide what action you want to perform on onClick function
onClick={() => {
if(this.props.type == 'update')
this.props.updateData(this.state.filterArray);
else
this.parseInput()
}}
You can use same property type (or anything you like) to render different labels
{{this.props.type=='update'? 'Генерировать': 'Обучить'}}
I assume that you want to make a component reusable? In that case you might want to design your component like so.
const NewButton = ({onClick, children}) => (
<Button
variant="contained"
color="primary"
style={{
background: "linear-gradient(45deg, #00ACD3 30%, #00BE68)
}}
onClick={onClick}>
children
</Button>);
Then your above snip becomes
<NewButton onClick={someFunction}>Something</NewButton>
<NewButton onClick={otherFunction}>Something</NewButton>
This is the basic idea behind any component-based front-end framework and I suggest you go to the react tutorials to learn more.
Otherwise, there are plenty of good articles about the topic out there
If I understand you correctly, you want to use the same component but make them do different things, on click for example.
Here is an example of how you can do it.
import React from 'react';
const Button = ({onClick}) => {
return (
<button
onClick={onClick}
>
Click on me
</button>
)
}
export default Button;
So when you want to pass down a method to the button, you can do it like this.
import Button from './button';
clickerTicker() {
alert("First method, clickerticker");
}
secondaryClick() {
alert("Second method yo");
}
render() {
return (
<div>
<ButtonComponent onClick={this.clickerTicker.bind(this)}/>
<br/>
<ButtonComponent onClick={this.secondaryClick.bind(this)}/>
</div>
);
}
Just pass the onClick to the component

Resources