React DatePicker toggle issue - javascript

i'm using this plugin in my project.
https://reactdatepicker.com
There is have some prop showTimeSelect this prop takes boolean value and hide or show time picker.
I'm trying to give option to user about selecting time picker, so i tried to make some onClick event and make this prop conditional.
But it's work sometimes, sometimes not..
I don't understand where is the problem here is my code:
import React from "react";
import ReactDOM from "react-dom";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "./styles.css";
class App extends React.Component {
state = {
startDate: new Date()
};
handleChange = date => {
this.setState({
startDate: date,
showTime: false
});
};
showTimeSelection = () => {
this.setState({
showTime: !this.state.showTime
});
};
render() {
return (
<div>
<DatePicker
selected={this.state.startDate}
onChange={this.handleChange}
showTimeSelect={this.state.showTime}
>
{" "}
<div>
<a onClick={() => this.showTimeSelection()}>
TOGGLE TIME SELECTION
</a>
</div>{" "}
</DatePicker>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
and here is the codesandbox example
You can try on codeSandBox it's sometimes work directly sometimes you need to click outside of datepicker and click inside again.

I have noticed it only works if showTimeSelect is true before the DatePicker is going to be displayed. So, before closing DatePicker you have to set showTimeSelect to true. you can do it in prop onClickOutside
state = {
startDate: new Date(),
showTime: true
};
handleChange = date => {
this.setState({
startDate: date
});
};
showTimeSelection = () => {
this.setState({
showTime: !this.state.showTime
});
};
render() {
const { startDate, showTime } = this.state;
return (
<div>
<DatePicker
selected={startDate}
onChange={this.handleChange}
showTimeSelect={showTime}
onClickOutside={() => this.setState({ showTime: true })}
>
<div onClick={this.showTimeSelection} style={{ cursor: "pointer" }}>
<h4>TOGGLE TIME SELECTION</h4>
</div>
</DatePicker>
</div>
);
}
}
check out code sandbox . check out two other useful props onCalendarClose and onCalendarOpen

Related

react component not rerendering when props change

I'm trying to create a modal that asks users if they're an individual or organization, and then shows a sign up modal specific to that type of user. This is what I have so far:
parent:
this.state = {
showInd: false,
showOrg: false,
};
changeInd = () => {
this.setState({
showInd: !this.state.showInd
});
this.props.onClose(); //this closes the initial modal
}
//exact same syntax for changeOrg
render(){
return(
<div onClick={this.changeInd}>
<FontAwesomeIcon icon={faUser} className="fa-7x icon"/>
<span>individual</span>
</div>
<div onClick={this.changeOrg}>
<FontAwesomeIcon icon={faUsers} className="fa-7x icon"/>
<span>organization</span>
</div>
<SignUpInd show={this.state.showInd} />
<SignUpOrg show={this.state.showOrg} />
)}
and the child:
render(){
if (this.props.show){
return(
<various sign up html>
)}
}
The parent component is re-rendering when the state changes, but the child component is not, even though the props are changing. I've tried using componentDidUpdate, but that is also never triggered when the props change here.
What could I be doing wrong?
EDIT: So I've realized that if I comment out the line that closes the initial modal with a callback function, the signUpInd modal will render properly. Why can I not do both?
this works:
import React from "react";
import SignUpInd from "./SignUpInd";
import SignUpOrg from "./SignUpOrg";
import "./styles.css";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showInd: false,
showOrg: false
};
}
showInd = () => {
this.setState((state) => ({ showInd: !state.showInd }));
};
showOrg = () => {
this.setState((state) => ({ showOrg: !state.showOrg }));
};
render() {
return (
<React.Fragment>
<div onClick={this.showInd}>
<FontAwesomeIcon icon={faUser} className="fa-7x icon"/>
<span>individual</span>
</div>
<div onClick={this.showOrg}>
<FontAwesomeIcon icon={faUsers} className="fa-7x icon"/>
<span>organization</span>
</div>
<SignUpInd show={this.state.showInd} />
<SignUpOrg show={this.state.showOrg} />
</React.Fragment>
);
}
}
1.At the parent component use a function that changes the state.
state = {
showInd: false,
showOrg: false,
};
stateChange = () =>{
this.setState({showInd:!this.state.showInd})
}
2.Use an onClick function on the div it will give opposite value of what it is right now and pass it as a props to the next component
<div onClick={this.stateChange}> //this onClick just flips showInd to the opposite of what it is currently - that's working properly
<span>individual</span>
</div>
<SignUpInd show={this.state.showInd} stateChange= {this.stateChange} />
3.At the other end just recieve the props and console log it
const {show,stateChange} = this.props
console.log(show);

Need tabs to hold their own state, so it can hold its own number of items within

import axios from 'axios';
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import StarIcon from '#material-ui/icons/Star';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import Paper from '#material-ui/core/Paper';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import TwitterIcon from '#material-ui/icons/Twitter';
import CloseIcon from '#material-ui/icons/Close';
import Highlighter from 'react-highlight-words';
class TwitterBot extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleTabState = this.handleTabState.bind(this);
}
state = {
loaded: [],
searched: [],
searchedTicker: '',
actveTab: '',
addedTickers: []
};
async componentDidMount() {
//Gathering data from heroku API I built and adding tweets to loaded array state
let feed = await axios.get('https://boiling-plains-63502.herokuapp.com/');
let tweets = feed.data;
this.setState({
loaded: tweets
});
}
handleChange = (e) => {
//Watching input and changing searchedTicker string while typing
this.setState({ searchedTicker: e.target.value });
};
handleTabChange = (event, newValue) => {
//Selecting the correct tab
this.setState({ tabValue: newValue });
};
handleTabState = (e, data) => {
//This is changing searchedTicker state to the value of whichever tab is clicked
this.setState({ searchedTicker: data });
};
showAll = () => {
//Clearing searched state
this.setState({ searchedTicker: '' });
};
addTicker = () => {
// Adding ticker to saved list
if (this.state.searchedTicker.length > 0) {
this.setState((state) => {
const tickers = state.addedTickers.push(state.searchedTicker);
return {
tickers,
searchedTicker: ''
};
});
} else {
alert('Plase enter a symbol to search');
}
};
removeTicker = (e, data) => {
// Removing tab
let tickers = this.state.addedTickers;
if (tickers.indexOf(data) === 0) {
tickers.shift();
this.showAll();
console.log('zero');
} else {
tickers.splice(tickers.indexOf(data));
this.showAll();
}
};
savedTickerFilter = (f) => {
this.setState({ searchedTicker: f.target.value });
};
render() {
//Trimming searched input to all lowercase and filtering displayed post within return based on search
let loaded = this.state.loaded,
searchedTicker = this.state.searchedTicker.trim().toLowerCase();
if (searchedTicker.length > 0) {
loaded = loaded.filter(function(i) {
return i.text.toLowerCase().match(searchedTicker);
});
}
//Copying loaded state and attempting to added individual numbers of tweets to each tab
let copyOfLoaded = [ ...this.state.loaded ];
let filterCopy = copyOfLoaded.filter(function(i) {
return i.text.toLowerCase().match(searchedTicker);
});
let numOfTweets = filterCopy.length;
return (
<div className="main" style={{ marginTop: 40 + 'px' }}>
<h4>Search a stock symbol below to find relevant tweets from Stocktwitz.</h4>
<h4>You may then press Add to Favorites to create a saved tab for later reference.</h4>
<div className="main__inner">
<TextField
type="text"
value={this.state.searchedTicker}
onChange={this.handleChange}
placeholder="Search Ticker..."
id="outlined-basic"
label="Search"
variant="outlined"
/>
<Button onClick={this.addTicker} variant="contained" color="primary">
Add to favorites <StarIcon style={{ marginLeft: 10 + 'px' }} />
</Button>
</div>
{/* This will be the Filter Tabs component and that will import the list thats below the Paper component below */}{' '}
<Paper square>
<Tabs indicatorColor="primary" textColor="primary" onChange={this.handleTabChange}>
<Tab label={<div className="tabs-label">All ({loaded.length})</div>} onClick={this.showAll} />
{//Mapping through tabs that are added in TwitterBot component and passed down as props to this component
this.state.addedTickers.map((i) => {
return (
<div className="tab-container">
<Tab
label={
<div className="tabs-label">
{i}
({numOfTweets})
</div>
}
key={i}
onClick={(e) => this.handleTabState(e, i)}
/>
<CloseIcon value={i} onClick={(e) => this.removeTicker(e, i)} />
</div>
);
})}
</Tabs>
</Paper>
<List className="tweets">
{loaded.map(function(i) {
return (
<ListItem key={i.id}>
{' '}
<TwitterIcon style={{ marginRight: 10 + 'px', color: '#1da1f2' }} />
<Highlighter
highlightClassName="YourHighlightClass"
searchWords={[ searchedTicker ]}
autoEscape={true}
textToHighlight={i.text}
/>,
</ListItem>
);
})}
</List>
</div>
);
}
}
export default TwitterBot;
Above is the entire component that holds all necessary logic.
I basically want {{numOfTweets}} within the tab-label to be static to each Tab thats mapped through once created. Right now it correctly will show how many items per tab there are while searching, and if clicked on current tab, but all tabs will react. I need them to stay static after search so if clicked on another tab, the past tab will still show how many tweets there were for that searched tab. Right now it's happening just because it's referencing the global loaded state, I just need way to copy that and render each one individually. I hope I explained that clear enough. You can see what I mean on my demo here: https://5ec5b3cfc2858ad16d22bd3c--elastic-khorana-7c2b7c.netlify.app/
I understand I need to break out and componentize this more, but I know theres has to be an easy solution, somehow using a simple functional component to wrap the Tab component or simple just the number that will be displayed. (I'm using Material UI)
Thank you, anything helps, just need to wrap my head around it.
Please check the codesandbox here https://codesandbox.io/s/proud-leftpad-j0rgd
I have added an object instead of a string for Addedtickers so that the count can be tracked and remains constant throughout. You can further optimize this , if you want to search again within each individual tab, but you get the gist.
Please let me know if this works for you

React Calling Parent's Method Nothing Happens

Probably a simple question and have so many people answered here but in this scenario, I cannot figure out why it doesn't work ...
In the parent I have
updateAccountNumber = value => {
console.log(value);
};
<Child updateAccountNumber={this.updateAccountNumber} />
In the child I have
<ListItem
button
key={relatedSub.office + relatedSub.account}
onClick={() =>
this.props.updateAccountNumber(
relatedSub.office + relatedSub.account
)
}
Even if I do parent like this, still no help..
<Child updateAccountNumber={() => this.updateAccountNumber()} />
if I have the below child item, then when I click on the menu that runs the child items, the component calls itself as many items as there are...
onClick={this.props.updateAccountNumber(
relatedSub.office + relatedSub.account
)}
It won't even run the below code, simple code, I can't see why it wouldn't kick of the handleClick event...
import React, { Component } from "react";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
const handleClick = () => {
debugger;
alert("sda");
console.log("bbb");
};
export default class RelatedSubAccounts extends Component {
Links = () => {
if (this.props.RelatedSubAccounts) {
let RelatedSubArray = this.props.RelatedSubAccounts;
let source = RelatedSubArray.map(relatedSub => (
<ListItem
button
onClick={handleClick}
key={relatedSub.office + relatedSub.account}
className={
relatedSub.office + relatedSub.account !== this.props.OfficeAccount
? ""
: "CurrentRelatedSub"
}
>
<ListItemText primary={relatedSub.office + relatedSub.account} />
</ListItem>
));
return (
<div id="RelatedSubLinks">
<List>{source}</List>
</div>
);
} else {
return "";
}
};
render() {
return this.Links();
}
}
Please ask if any other related code is missing, and I can share.
I was able to get an example that works with the code you shared by using RelatedSubAccounts like this:
<RelatedSubAccounts RelatedSubAccounts={[{ office: 1, account: 2 }]} />
Code Sandbox Example
I see a few things that stand out as potentially confusing. I will point them out in code below with comments:
import React, { Component } from "react";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemText from "#material-ui/core/ListItemText";
const handleClick = () => {
debugger;
alert("RelatedSubAccounts clicked");
console.log("bbb");
};
export default class RelatedSubAccounts extends Component {
// Capitalization like this in react normally indicates a component
Links = () => {
/*
Having a prop that is the same name as the component and capitalized is confusing
In general, props aren't capitalized like the component unless you are passing a component as a prop
*/
if (this.props.RelatedSubAccounts) {
// Again, capitalization on RelatedSubArray hints that this is a component when it really isn't
let RelatedSubArray = this.props.RelatedSubAccounts;
let source = RelatedSubArray.map(relatedSub => (
<ListItem
button
onClick={handleClick}
key={relatedSub.office + relatedSub.account}
className={
relatedSub.office + relatedSub.account !== this.props.OfficeAccount
? ""
: "CurrentRelatedSub"
}
>
<ListItemText primary={relatedSub.office + relatedSub.account} />
</ListItem>
));
return (
<div id="RelatedSubLinks">
<List>{source}</List>
</div>
);
} else {
return "";
}
};
render() {
return this.Links();
}
}
This is going to be strangest solution but might give you a lesson or two.. I found the cause of the issue here.
So I have a menu like this
When you click on that arrow to open up the menu, it becomes active and when you click away onBlur kicks in and that menu goes away.. (menu created used react-select Creatable)
DropdownIndicator = props => {
return (
<div
onBlur={() => {
this.setState({ Focused: false, RelatedSub: false });
}}
so I had to update it to below:
onBlur={() => {
this.setState({ Focused: false });
setTimeout(() => {
this.setState({ RelatedSub: false });
}, 100);
}}

How can I edit the value of the timepicker from the keyboard?

I have a material-ui-time-picker and I want to control this input, it works well, but I want to edit the time input from the keyboard and not when I click the input on the clock.
My code is :
import React, { Component } from "react";
import { TimePicker } from "material-ui-time-picker";
import { Input as Time, Dialog as Clock } from "#material-ui/core";
openDialog = () => this.setState({ isOpen: true });
closeDialog = () => this.setState({ isOpen: false });
handleDialogTimeChange = newValue => {
const hours = newValue
.getHours()
.toString()
.padStart(2, "0");
const minutes = newValue
.getMinutes()
.toString()
.padStart(2, "0");
const textValue = hours + ":" + minutes;
this.setState({ time: textValue });
};
handleKeyboardTimeChange = time => this.setState({ time });
createDateFromTextValue = value => {
const splitParts = value.split(":");
return new Date(1970, 1, 1, splitParts[0], splitParts[1]);
};
render() {
return (
<div>
<Time
value={this.state.time}
onChange={this.handleKeyboardTimeChange}
endAdornment={
<InputAdornment position="end">
<IconButton onClick={this.openDialog}>
<AccessTime />
</IconButton>
</InputAdornment>
}
//}
/>
<Clock maxWidth="xs" open={this.state.isOpen}>
<TimePicker
mode="24h"
value={this.createDateFromTextValue(this.state.time)}
onChange={this.handleDialogTimeChange}
autoOk={true}
cancelLabel=""
okLabel=""
placeholder=""
disableUnderline={true}
/>
</Clock>
</div>
);
}
My sandbox: https://codesandbox.io/s/vm9wm19p27
When I run it, I get this input, but when I edit his value, the input will be disappeared.
How can I fix it ?
I've forked your sandbox and made a couple of adjustments. Though I've not fixed it - I'll just show you what's currently wrong.
https://codesandbox.io/s/j24rqql9n9
I modified two lines
In your constructor, I added
this.handleKeyboardTimeChange = this.handleKeyboardTimeChange.bind(this)
And your handleKeyboardTimeChange:
handleKeyboardTimeChange(event) {
this.setState({ time: event.target.value });
}
This simply sets the state to exact value passed in from what you see there. No additional validation.

Unable to get Material-Ui datepicker date on the first change

So I am unable, to get date from material-ui dateandtimepicker on the first select, somehow, i get value only on second click, and that value is previous one,
Also would love to know if there is any other way to convert date to format like this yyyy:mm:dd:hh:mm without using moment.js
Here is my code:
import React, { Component } from 'react'
import DataPicker from './UI-components/DataPicker'
class EventForm extends Component {
constructor(props) {
super(props);
this.state = {
text: '',
errors: {},
start:'',
end:''
}
}
onChange1(e) {
this.setState({
start: e.target.value,
});
console.log(this.state.start)
}
render() {
return (
<div>
<DataPicker
label="Event Starts"
onChange={this.onChange1.bind(this)}
defaultas="2017-05-24T10:30"
/>
</div>
)
}
}
export default EventForm;
DatePicker.js
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
const styles = theme => ({
container: {
display: 'flex',
flexWrap: 'wrap',
},
textField: {
marginLeft: theme.spacing.unit,
marginRight: theme.spacing.unit,
width: 300,
},
});
function DateAndTimePickers(props) {
const { classes } = props;
return (
<form className={classes.container} noValidate>
<TextField
id="datetime-local"
label={props.label}
type="datetime-local"
defaultValue={props.defaultas}
className={classes.textField}
onChange = {props.onChange}
value = {props.value}
InputLabelProps={{
shrink: true,
}}
/>
</form>
);
}
DateAndTimePickers.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(DateAndTimePickers);
You are not passing down the value to the DatePicker component. You could use start as value to control the DatePicker and ignore the defaultValue entirely.
The reason why console.log(this.state.start) in your onChange1 handler isn't displaying the start you would think is because setState is asynchronous, which means this.state.start will not have been updated yet.
class EventForm extends Component {
state = {
text: '',
errors: {},
start: '2017-05-24T10:30',
end: ''
};
onChange1 = (e) => {
this.setState({
start: e.target.value,
});
};
render() {
return (
<div>
<DataPicker
label="Event Starts"
onChange={this.onChange1}
value={this.state.start}
/>
</div>
)
}
}
i don't know much about react but this might help with the formatting of the dates;
<td>
{new Intl.DateTimeFormat('en-GB', {
year: 'numeric',
month: 'long',
day: '2-digit'
}).format(customer.firstSale)}
</td>
Example from here;
Well you are getting old one means last set value in state cause you are doing things simultaneously/parallelly both set value and console value. Means you know JS is async you are doing here
onChange1(e) {
this.setState({
start: e.target.value,
});
console.log(this.state.start)
}
what is happening here setting the new value to state and console current/last/default(first time) state value, That's why you are getting it the second time.
to get current one do like this:
onChange1(e) {
this.setState({
start: e.target.value,
},function(whatever){
console.log(this.state.start)
});
}
it will execute and console value once your set state is done.
And for formatting date without momentjs you can find the source of momentjs what they are doing under the hood obviously they are using JS. If I were you I'll do this way. Haha

Categories