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

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

Related

The first task in my React Js tasklist project is always undefined

I have been creating a react js project which is a task list. However I have been facing an error, for some reason I have found multiple errors. First for debugging purposes I created a handle delete function which will log a string to the console to show that it has been triggered. It is only meant to be triggered when the X button on the task element is clicked, however, it triggers whenever I submit the text input to create a new task. Secondly the biggest error is that the first element is always undefined no matter what I type. How do I fix this problem.
import React, { Component } from "react";
import ReactDOM from "react-dom";
import TaskList from "./index2";
class Tests extends Component {
constructor(props) {
super(props);
this.state = {
value: "",
object: {},
object2: [],
};
this.updateInputValue = this.updateInputValue.bind(this);
this.submit = this.submit.bind(this);
}
updateInputValue(evt) {
this.setState({
value: evt.target.value,
});
}
submit() {
if (this.state.value.trim() != "") {
this.setState({
object: { task: this.state.value.trim(), id: Date.now },
object2: [...this.state.object2, this.state.object],
value: "",
});
} else {
return;
}
}
render() {
return (
<div>
<label for="text">Text 1</label>
<br />
<input
type="text"
label="text"
onChange={(evt) => this.updateInputValue(evt)}
onSubmit={this.submit}
value={this.state.value}
/>
<br />
<button onClick={this.submit} style={{ height: 50, width: 60 }}>
Submit
</button>
<br></br>
<TaskList
allTasks={this.state.object2}
handleDeleteFunction={console.log("handle delete has been triggered")}
/>
</div>
);
}
}
export default Tests;
ReactDOM.render(<Tests />, document.getElementById("root")
);
And my taskList code
import React from "react";
import "./woah.css";
export default function TaskList({ allTasks, handleDeleteFunction }) {
return (
<ul>
{allTasks.map(({ task, id }) => (
<li key={id} id="task">
<p>{task}</p>
<button onClick={() => handleDeleteFunction}>X</button>
</li>
))}
</ul>
);
}
Try this:
submit() {
if (this.state.value.trim() != "") {
const newObj = { task: this.state.value.trim(), id: Date.now };
this.setState({
object: newObj,
object2: [...this.state.object2, newObj],
value: "",
});
} else {
return;
}
}
You are referencing the current object in state, which is empty.

React DatePicker toggle issue

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

onChange input type[checkbox] not working with Vue styled components

This is my simple functional component in Vuejs
import { Label, Input, Checkmark } from "./styles";
export default {
functional: true,
model: {
prop: "checked",
event: "change"
},
props: {
checked: Boolean
},
// eslint-disable-next-line
render(h, { props, listeners}) {
console.log(listeners);
const changeHandler = listeners.change ? listeners.change : () => {};
return (
<Label>
<Input
type="checkbox"
checked={props.checked}
onChange={e => {
console.log("checked", e.target.checked);
changeHandler(e);
}}
/>
<Checkmark class="checkmark" />
</Label>
);
}
};
The component simply won't console.log when used like
<VCheckbox
checked={this.checkSelections[idx]}
onChange={e => {
this.$set(this.checkSelections, idx, e.target.checked);
}}
/>
I'm using Vuejs - 2.5.x
If I console.log my listeners they definitely log change.
Second, if I use nativeOnChange instead, it does fire.
Last and importantly, In the very same fashion, I also have a button component (functional ) and it works fine with onClick ( no use of native there ). Can anyone please let me know what's going on ?
Update -
Similar is the case with nativeOnMouseover.

react-big-calendar ERROR: Invalid prop `slotStart` of type `date` supplied to `Popup`, expected `number`

I'm using the prop "popup" for react-big-calendar and I'm getting the above error in the console upon clicking the "+x more" link. My onEventClick function works by routing me to "calendar/" but I'm not sure what I'm missing here. I read through some documentation but couldn't find the right example to solve the issue. I suspect it has something to do with "moment," or improper formatting of the date object.
import React from "react";
import BigCalendar from "react-big-calendar";
import moment from "moment";
import "react-big-calendar/lib/css/react-big-calendar.css";
const localizer = BigCalendar.momentLocalizer(moment);
let allViews = Object.keys(BigCalendar.Views).map(k => BigCalendar.Views[k]);
class Calendar extends React.Component {
onEventChange = event => {
this.onEventClick(event);
};
onEventClick = event => {
this.setState({
endDate: moment(event.end.toLocaleString()).format("YYYY-MM-DDTHH:mm"),
startDate: moment(event.start.toLocaleString()).format("YYYY-MM-DDTHH:mm"),
eventName: event.name
});
this.props.history.push("calendar/" + event.eventId);
};
render () {
function Event({ event }) {
return (
<span id="eventTitle">
{event.number +
" - " +
event.name}
</span>
);
}
return(
<React.Fragment>
<div style={{ height: 700 }}>
<BigCalendar
localizer={localizer}
toolbar={true}
events={this.state.events}
popup
selectable
onSelectSlot={(slotInfo) => alert(
`selected slot: \n\nstart ${slotInfo.start.toLocaleString()} ` +
`\nend: ${slotInfo.end.toLocaleString()}`
)}
views={allViews}
components={{
event: Event
}}
onSelectEvent={event => this.onEventChange(event)}
eventPropGetter={(event) => {
let newStyle = {
backgroundColor: "",
color: "white",
borderRadius: "5px",
border: "none"
};
if (event.eventStatusCd === "CL ") {
newStyle.backgroundColor = "firebrick";
}
return {
className: "",
style: newStyle
};
}}
/>
</div>
</React.Fragment>
);
}
}
export default Calendar;
Here's a sample from the "start" property for an event object.
This object gets pushed into an array of other event objects:
eventObj.start = new Date(
Date.parse(
moment
.utc(dateCreated)
.local()
.format("YYYY-MM-DDTHH:mm")
)
);
I ran into similar issues, when first implementing. While react-big-calendar uses an internal localizer (in your case it's probably Moment), it still expects that, in the events that you provide it, all start and end dates must be valid JS Date Objects. My suggestion is, rather than running Date.parse(), you do something like:
eventObj.start = moment(dateCreated).local().toDate(); // returns valid JS Date Object

Using a higher order component with multiple Draft.js editors in single page

I am working on a homepage that consists of eight different components representing various aspects of the page content. I want to have three of them be editable using a custom built InlineEditor component that uses Draft.js. When I tried to do this initially, the editing toolbars for the second and third component would only work on the first component. So this is a Draft.js issue. I was able to get everything to work by creating three separate InlineEditor components and then using each one individually when necessary, but that seems redundant.
I'm thinking there has to be a better way to do this using HOCs or render props but I'm struggling to set that up properly. Any ideas on what might be a better way to go about this?
Here's the initial InlineEditor component:
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { EditorState, convertFromRaw } from 'draft-js'
import Editor from 'draft-js-plugins-editor'
import createUndoPlugin from 'draft-js-undo-plugin'
import createToolbarPlugin, { Separator } from 'draft-js-static-toolbar-plugin'
import createToolbarLinkPlugin from 'draft-js-toolbar-link-plugin'
import {
ItalicButton,
BoldButton,
UnderlineButton,
CodeButton,
HeadlineOneButton,
HeadlineTwoButton,
HeadlineThreeButton,
UnorderedListButton,
OrderedListButton,
BlockquoteButton,
CodeBlockButton
} from 'draft-js-buttons'
import { Flex, Box } from 'rebass'
import FontAwesome from 'react-fontawesome'
import {
ToolbarNav,
EditPanel,
StaticToolbar,
TextInfo,
DefaultButton,
SuccessButton,
InlineLink
} from 'styles'
// Set up Draft.js toolbar and plugins
const undoPlugin = createUndoPlugin()
const toolbarLinkPlugin = createToolbarLinkPlugin({
inputPlaceholder: 'Insert URL here...'
})
const { LinkButton } = toolbarLinkPlugin
const { UndoButton, RedoButton } = undoPlugin
const toolbarPlugin = createToolbarPlugin({
structure: [
BoldButton,
ItalicButton,
UnderlineButton,
CodeButton,
Separator,
HeadlineOneButton,
HeadlineTwoButton,
HeadlineThreeButton,
Separator,
UnorderedListButton,
OrderedListButton,
BlockquoteButton,
CodeBlockButton,
LinkButton,
Separator,
UndoButton,
RedoButton
]
})
const { Toolbar } = toolbarPlugin
const plugins = [toolbarPlugin, toolbarLinkPlugin, undoPlugin]
class InlineEditor extends Component {
displayName = 'inline editor component'
constructor(props) {
super(props)
this.state = {
editorState: EditorState.createWithContent(
convertFromRaw(this.props.rawContent)
),
showURLInput: false,
urlValue: '',
readOnly: true
}
}
onChange = editorState => this.setState({ editorState })
focus = () => this.refs.editor.focus()
onEdit = e => {
e.preventDefault()
this.setState({
readOnly: false
})
}
onSave = () => {
// save new content
this.setState({
showURLInput: false,
urlValue: '',
readOnly: true
})
}
onCancel = () => {
// cancel editing
this.setState({
editorState: EditorState.createWithContent(
convertFromRaw(this.props.rawContent),
this.decorator
),
showURLInput: false,
urlValue: '',
readOnly: true
})
}
renderToolbar = () => {
return (
<ToolbarNav>
<StaticToolbar>
<Toolbar />
</StaticToolbar>
</ToolbarNav>
)
}
render() {
const { editorState, readOnly } = this.state
const { auth } = this.props
return (
<EditPanel>
<Flex wrap>
<Box w={'90%'}>{!readOnly && this.renderToolbar()}</Box>
<Box mt={1}>
<Editor
editorState={editorState}
onChange={this.onChange}
plugins={plugins}
ref="{(element) => { this.editor = element }}"
readOnly={readOnly}
/>
{auth.isAuthenticated &&
readOnly && (
<TextInfo>
<InlineLink onClick={this.onEdit} title="Edit">
<FontAwesome name="pencil" /> Edit
</InlineLink>
</TextInfo>
)}
</Box>
<Box width={'40%'} mr={1} mt={1}>
{!readOnly && (
<DefaultButton
className={`block`}
type="button"
onClick={this.onCancel}>
Cancel
</DefaultButton>
)}
</Box>
<Box width={'40%'} mt={1}>
{!readOnly && (
<SuccessButton
className={`block`}
type="button"
onClick={this.onSave}>
Save
</SuccessButton>
)}
</Box>
</Flex>
</EditPanel>
)
}
}
const mapStateToProps = state => {
return {
auth: state.auth
}
}
export default connect(mapStateToProps)(InlineEditor)
Currently this is being accessed by components such as About like so:
return (
<InlineEditor
auth={ this.props.auth }
rawContent={ about }/>
)
I was able to solve this problem by creating one InlineEditor component that passed in the toolbar plugins inside of its constructor, i.e.
constructor(props) {
super(props)
this.undoPlugin = createUndoPlugin()
this.toolbarLinkPlugin = createToolbarLinkPlugin({
inputPlaceholder: "Insert URL here...",
})
// etc...
}

Categories