how to open airbnb SingleDatePicker calendar on focus - reactjs

Am trying to include a airbnb SingleDatePicker in my component as shown below
import "react-dates/initialize";
import "react-dates/lib/css/_datepicker.css";
import { SingleDatePicker } from "react-dates";
export default class ExpenseForm extends React.Component {
constructor(props) {
super(props);
this.state = {
createdAt: moment(),
calendarFocused: false
};
this.onDateChange = this.onDateChange.bind(this);
this.onFocusChange = this.onFocusChange.bind(this);
}
onDateChange(createdAt) {
this.setState(() => ({ createdAt }));
}
onFocusChange({ focused }) {
this.setState(() => ({
focused
}));
}
render() {
return (
<div>
<SingleDatePicker
date={this.state.createdAt}
startDateId="MyDatePicker"
onDateChange={this.onDateChange}
focused={this.state.calendarFocused}
onFocusChange={this.onFocusChange}
id="SDP"
/>
</div>
);
}
}
It shows the current date inside the inside the input box as shown below but when i click on the field nothing happens(Calendar widget not opening).
Am not getting any errors in the console to figure out what is the issue. Could anyone please help me on fixing this issue?

It looks like you are targeting the wrong state key in your onFocusChange function. Try changing the function to this:
onFocusChange({ focused }) {
this.setState({ calendarFocused: focused });
}
Notice I also removed the anonymous function from inside of your setState call. You can remove it from your onDateChange function as well:
onDateChange(createdAt) {
this.setState(({ createdAt }));
}
I also noticed that you're using the startDateId prop that is not available for the SingleDatePicker. Airbnb uses that for the DateRangePicker to determine which input to focus on. There is only one input in the SingleDatePicker, so it does not require that prop. You can remove that prop without any change to your functionality.

1- correct this handler
onFocusChange = ({ focused }) => {
this.setState(() => ({ calendarFocused: focused }));
};
2- import 'react-dates/initialize'; //dependency as of v13.0.0
3-since u r not using webpack
Create a CSS file with the contents of require.resolve('react-dates/lib/css/_datepicker.css') and include it in your html section.
To see this in action, you can check out https://github.com/majapw/react-dates-demo which adds react-dates on top of a simple create-react-app setup.

Related

componentdidmount - prop-types validation

Thank you for your time.
Noob React question... i know componentDidMount will fire after the first render of the component, which is why the prop-types eslint error i am getting is being triggered. However i am not sure how you would fix this and add validation, propTypes validation fires before the getArticles() function therefore if i declare a propTypes it returns undefined... as i.e. articles has not been defined until after the first render and and componentDidMount is called... have had a good dig and cant see a simple solution for what i assume is a common problem??
Question - how do you validate props that have not yet been fetched.
class ArticlesList extends Component {
componentDidMount() {
this.props.getArticles();
}
render() {
return this.props.articles.map(({ id, date, heading, body }) => (
<Article key={id} date={date} heading={heading} body={body} />
));
}
}
const mapStateToProps = (state) => {
return { articles: state.articles };
};
export default connect(mapStateToProps, { getArticles })(ArticlesList);
you would only get an issue for an undefined prop if you had add to your prop validation isRequired like PropTypes.array.isRequired. With that in mind you only need to define correctly your propType:
ArticlesList.propTypes = {
articles: PropTypes.array,
}
Destructure the componentDidMount i.e.
componentDidMount() {
{ getArticles } = this.props;
getArticles();
}
and adding
ArticlesList.propTypes = {
getArticles: PropTypes.func,
articles: PropTypes.array,
};

RadioButton click TypeError: Cannot read property 'setState' of undefined

I'm trying to set the state based on the radio button clicked.
My Code:
import React, { Component } from 'react';
class MyApp extends Component {
state={
name: "SomeName",
radio: "some"
}
onRadioChange(e) {
this.setState({name:"New Name"});
// this.setState({
// [e.target.name]: e.target.value;
// })
}
render() {
return (
<div style={{marginBottom:"50px"}}>
<input type="radio" onChange = {this.onRadioChange}
value="JonSnow"
name="radio1" />
<label>JonSnow</label>
<input type="radio" onChange = {this.onRadioChange}
value="Cleopatra"
name="radio1"/>
<label>Cleopatra</label>
</div>
);
}
}
export default MyApp;
Whenever I click on the radio button, I get an error:
TypeError: Cannot read property 'setState' of undefined
What am I doing wrong?
In order to use this keyword, you need to bind the method. Or as a workaround you can use the arrow function.
Like this:
onRadioChange = (e) => {
this.setState({name:"New Name"});
// this.setState({
// [e.target.name]: e.target.value;
// })
}
You have two options here. Either use arrow function or bind your function to this inside your constructor.
Why is it not working?
This is because in order to use setState anywhere you must have access to this.
Arrow functions do not need to be explicitly bound to this and since is a shorter choice for achieving what you want. (They are bound to this beforehand).
First option:
onRadioChange = (e) => {
this.setState({ name: 'newName' });
}
Second option:
class MyApp extends React.Component {
constructor(props) {
super(props);
this.onRadioChange = this.onRadioChange.bind(this);
};
}

ReactJS : How to properly handle data fetched from food2fork API?

I have an app built with ReactJS. Its purpose is to display recipes, searched in food2fork API.
I have no problems with updating state of parent component. Data is fetched after clicking 'search' button in app.
My issue is related with sending fetched data as props to child component and properly displaying received recipes based on current search.
handleChange is only for handling input.
handleSearch is what I wanted to use 'onClick' of a button to display data fetched from API.
Fetched recipes should be displayed in Results component.
Hope it is clear :)
Besides only passing state as props from Parent component and using it in Child component, I also tried to update Child state based on received props with lifecycle methods - maybe I haven't used them corrently ...
Parent component:
import React, { Component } from 'react';
import Results from './Results';
class Recipes extends Component {
constructor(props){
super(props);
this.state = {
search: '',
recipes: []
}
}
handleChange=e=>{
this.setState({
search: e.target.value
})
}
handleSearch =()=>{
if(this.state.search !== ''){
const url = `https://www.food2fork.com/api/search?key=367d2d744696f9edff53ec5b33a1ce64&q=${this.state.search}`
fetch(url)
.then(data => data.json())
.then(jsonData => {
this.setState((jsonData)=> {return {
recipes: jsonData}
})
})
} else {
console.log('empty')
}
}
render() {
return (
<Wrapper>
<SearchBar
value={this.state.search}
type='search'
onChange={this.handleChange}>
</SearchBar>
<SearchButton onClick={this.handleSearch}>SEARCH</SearchButton>
<Results recipes={this.state.search}/>
</Wrapper>
);
}
}
export default Recipes;
CHILD COMPONENT 'Results' which should receive updated recipe list as props and display these recipes.
import React from 'react';
import Recipe from './Recipe';
class Results extends React.Component {
render(){
return (
<Container>
<RecipesList>
{this.props.recipes.map(item =>
<Recipe
f2fURL={item.f2f_url}
image={item.image_url}
publisher={item.publisher}
publisherURL={item.publisher_url}
recipeID={item.recipe_id}
source={item.source_url}
title={item.title}
/>)}
</RecipesList>
</Container>
);
}
};
As #yourfavoritedev mentioned, you have a typo on Results props. It should be
recipes={this.state.recipes} instead of recipes={this.state.search}
You should also change:
this.setState((jsonData)=> {return {
recipes: jsonData}
})
for:
this.setState({ recipes: jsonData })
The updater function will be something like this (documentation here):
(state, props) => stateChange
So the jsonData you are using on your setState is actually the previous state and not the data coming from the api call.
Your problem is here
this.setState((jsonData)=> {return {
recipes: jsonData}
})
inside your ajax response.
Change this to
this.setState({recipes: jsonData});
This should set the recipes object correctly.

react office js textfield controlled component

i tried to use officejs react component in it and for osme reason i cant get it to work properly..effective here is the code. it works in codepen but when i put hte same code in excel addin project, i cant get the value in the textfields.
Code in codepen(it works):
[https://codepen.io/manish_shukla01/pen/ReWWmM][1]
Code in my project in app file(does not work in the sense that handlechange events are not getting fired i believe so value of my state.value1 remains blank even when i input anything):
import * as React from 'react';
import { Button, ButtonType } from 'office-ui-fabric-react';
import Header from './Header';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import * as OfficeHelpers from '#microsoft/office-js-helpers';
export default class App extends React.Component<any,any,any>{
constructor(props) {
super(props);
this.state = {
value1: '',
value2:'',
message:'Helloooo'
};
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange1(event) {
this.setState({value1: event.target.value});
}
handleChange2(event) {
this.setState({value2: event.target.value});
}
handleSubmit = async () => {
event.preventDefault();
this.setState({message: 'i got clicked'});
try {
//event.preventDefault();
await Excel.run(async context => {
/**
* Insert your Excel code here
*/
const range = context.workbook.getSelectedRange();
// Read the range address
range.load('address');
// Update the fill color
range.format.fill.color = 'blue';
range.values = [[this.state.value2]];
await context.sync();
console.log(`The range address was ${range.address}.`);
});
} catch(error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
};
}
render() {
return (
<form className='ms-welcome' onSubmit={this.handleSubmit}>
<Header logo='assets/logo-filled.png' title='Excel Analytics' message={this.state.message} />
<TextField label="field1"
value={this.state.value1} onChange={this.handleChange1}
required
/>
<Button className='ms-welcome__action' buttonType={ButtonType.primary}
onClick={this.handleSubmit}>Run
</Button>
</form>
);
}
}
I also faced same issue with Office UI Fabric TextField's "onChange" event and solved it using "onChanged" instead, which is deprecated as they say. But it worked for me.
First, add onChanged handler to TextField as below:
<TextField name="fieldName" label="field1" value={this.state.value1} onChanged={val => this.handleChange1("fieldName", val)} />
Also, note that "name" attribute is added to identify control in handleChange1.
Now change handler implementation as below:
handleChange1(name, value) {
this.setState(prevState => ({
result: {
...prevState.result,
[name]: value
}
}));
}
Hope this helps. Thanks!

Semantic-ui-react: How do I trigger a Popup without it being click/hover?

When submitting a form, I wish to show a small popup for 2.5 seconds if the server sends back a bad response.
The logic is fairly simple, however, I cannot figure out how to make this popup listen to a boolean somewhere in the state management(MobX in my case). I can get the content into the Popup just fine, however, the trigger is a button(and the content will show, if you click it) - But how do I make it listen to a boolean value somewhere?
Fairly simple class here:
import React from "react";
import { Popup, Button } from "semantic-ui-react";
import { inject } from "mobx-react";
const timeoutLength = 2500;
#inject("store")
export default class ErrorPopup extends React.Component {
state = {
isOpen: false
};
handleOpen = () => {
this.setState({
isOpen: true
});
this.timeout = setTimeout(() => {
this.setState({
isOpen: false
})
}, timeoutLength)
};
handleClose = () => {
this.setState({
isOpen: false
});
clearTimeout(this.timeout)
};
render () {
const errorContent = this.props.data;
if(errorContent){
return(
<Popup
trigger={<Button content='Open controlled popup' />}
content={errorContent}
on='click'
open={this.state.isOpen}
onClose={this.handleClose}
onOpen={this.handleOpen}
position='top center'
/>
)
}
}
}
However, the trigger value is a button which is rendered if this.props.data is present. But that's not the behavior I wish; I simply want the popup to render(and thus trigger) if this.props.data is there; alternatively, I can provide a true value with props if need be.
But how do I make this component trigger without it being a hover/button?
How about passing in the isOpen prop? Then you could add some logic onto the componentWillReceiveProps hook:
import React from "react";
import { Popup, Button } from "semantic-ui-react";
import { inject } from "mobx-react";
const timeoutLength = 2500;
#inject("store")
export default class ErrorPopup extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
}
};
//This is where you trigger your methods
componentWillReceiveProps(nextProps){
if(true === nextProps.isOpen){
this.handleOpen();
} else {
this.handleClose();
}
}
handleOpen = () => {
this.setState({
isOpen: true
});
this.timeout = setTimeout(() => {
//No need to repeat yourself - use the existing method here
this.handleClose();
}, timeoutLength)
};
handleClose = () => {
this.setState({
isOpen: false
});
clearTimeout(this.timeout)
};
render () {
const errorContent = this.props.data;
if(errorContent){
return(
<Popup
trigger={<Button content='Open controlled popup' />}
content={errorContent}
on='click'
open={this.state.isOpen}
position='top center'
/>
)
}
}
}
Without a need of handling delay - you could simply pass in the isOpen prop and that would do the trick.
And here what it could look like in your parent component's render:
let isOpen = this.state.isOpen;
<ErrorPopup isOpen={isOpen}/>
Set this value to control the popup, ideally, this should be a part of your parent component's state. Having a stateful component as a parent is important to make the popup re-rendered
Just use the property open as in the documentation. There is a separate example when popup is opened by default.

Resources