Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opening DatePicker manually #685

Closed
mir3z opened this issue Jan 4, 2017 · 27 comments
Closed

Opening DatePicker manually #685

mir3z opened this issue Jan 4, 2017 · 27 comments

Comments

@mir3z
Copy link

mir3z commented Jan 4, 2017

How to open it manually? Is there any API exposed or I have to trigger click event on input?

@alex-shamshurin
Copy link
Contributor

This is pretty simple:

<DatePicker
   ref={(c) => this._calendar = c}
   locale='ru'
    ...
   customInput={<InputField {...this.props} calendar={this._calendar}/>}
/>

And then somewhere
this._calendar.setOpen(bool)

@mir3z
Copy link
Author

mir3z commented Jan 14, 2017

@alex-shamshurin It is but setOpen is not documented in API so i treat it like a workaround or hack rather than a public API method.

@alex-shamshurin
Copy link
Contributor

No matter, it works! This is exaxtly is used inside.

@L-u-k-e
Copy link

L-u-k-e commented Jan 23, 2017

@alex-shamshurin It's generally considered bad practice to use the _ prefixed methods as they're meant to be private and are subject to change between releases.

@alex-shamshurin
Copy link
Contributor

That _calendar variable is in my code, not inside DatePicker. It's just a ref to calendar object, not related to DatePicker library at all.

@L-u-k-e
Copy link

L-u-k-e commented Jan 23, 2017

@alex-shamshurin oops I see that now. Sorry.

I wonder why setOpen isn't documented. Perhaps a separate issue should be opened to wrote docs for it.

@alex-shamshurin
Copy link
Contributor

I think so.

@martijnrusschen
Copy link
Member

Improvements to the docs are welcome! Thanks!

@alex-shamshurin
Copy link
Contributor

So setOpen is normal public method, as @martijnrusschen has just confirmed, we only need add this to the docs.

@tommyalvarez
Copy link

@alex-shamshurin in my case i don't have the possibility to use it as a public method, since i can't use the "ref" property of the component to assign it to a variable and the use the setOpen. Can you add it as a property or is there any other way to express directly in the render of an outer component that the DatePicker should start opened by default?

@alex-shamshurin
Copy link
Contributor

I really do not understand why you cannot get a reference to a component and use its methods and state. if you want it always be opened you can use withPortal or inline options. If you want it just to start opened you should get a reference and open it.

@tommyalvarez
Copy link

tommyalvarez commented Jun 15, 2017

@alex-shamshurin it's a little bit complicated to explain but basically, i'm using riek library for inline editing (values in a visual table). I'm extending that library to support inline datepicker editing. My extension class is:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import { RIEInput } from 'riek'
import moment from 'moment'
import DatePicker from 'react-datepicker'
import { I18n } from 'react-redux-i18n'

import 'react-datepicker/dist/react-datepicker.css'

const debug = require('debug')('RIEDate')

export default class RIEDate extends RIEInput {

  constructor(props) {
    super(props)
  }

  static propTypes = {
    format: PropTypes.func
  }

  // ... More code here omited for simplicity...

  renderNormalComponent = () => {
    debug(`renderNormalComponent()`)
    return <span
    tabIndex = "0"
    className = { this.makeClassString() }
    onFocus = { this.startEditing }
    onClick = { this.elementClick } {...this.props.defaultProps } > 
      { this.props.format ? this.props.format(this.state.newValue || this.props.value) : (moment(this.state.newValue).format(I18n.t("time.formats.calendar_date_js")) || moment(this.props.value).format(I18n.t("time.formats.calendar_date_js"))) } 
    </span>
  }

  renderEditingComponent = () => {
    debug(`renderEditingComponent()`)
    return <DatePicker  
      disabled={ this.props.shouldBlockWhileLoading && this.state.loading }
      placeholderText={ this.props.placeholder }
      className={ this.makeClassString() }
      selected={ moment(this.props.value) }
      onChange={ this.elementBlur }
      locale="es"
      **ref="input"**
      {...this.props.editProps }
    />
  }
}

This works by calling renderEditingComponent() when clicking a date value on a table column, which makes an input appears on top of it. That would be the <DatePicker ...>. Riek library needs the ref value of the input component be set as "input" so i can't really change it, otherwise it won't work or at least i will have to override bunch of methods.
Right now, upon clicking the value to be editted, the input will appear but the calendar won't open until i click again so i have to click twice to edit it.

@alex-shamshurin
Copy link
Contributor

Why you cannot wrap this ReactDatePicker component into custom your DatePicker or Calendar component and use ref="input" on its props whereas save real reference on DatePicker inside your internal component and pass it back via callback function?

@alex-shamshurin
Copy link
Contributor

@tommyalvarez And besides, you need a reference only for input, not for a DatePicker

@serkolch
Copy link

This really needs to be documented, I shouldn't have to go to the third page of issues in order to find this...
At the very least, a reference to this issue in the main .md

That aside, this is awesome!

@rafeememon
Copy link
Contributor

@serkolch, PRs for improvements to the docs are welcome

@poohsen
Copy link

poohsen commented Sep 4, 2017

the workaround doesn't work for me with v0.53.0.
The customInput line gives me a

expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

and setOpen gives

Cannot read property 'setOpen' of undefined

Any ideas are appreciated...

EDIT:
Seems I was confused as to what the this keyword was referring to in this case. It worked with a helper method outside the return method.
The customInput part is still borked, though.

@danwild
Copy link

danwild commented Jan 23, 2019

I'm a react/redux newb - so didn't immediately understand how the setOpen method might be exploited to wire up to redux.

Here's how I got the React parts to work for anyone else with same issue:

Create a ref to the calendar in your components constructor:

this.calendarRef = React.createRef();

Attach the ref to your calendar:

<DatePicker ref={this.calendarRef} />

Then you can use the ref to trigger the setOpen method:

<button onClick={() => {this.calendarRef.current.setOpen(true)}}>
  Open sesame
</button>

@stale
Copy link

stale bot commented Aug 30, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Aug 30, 2019
@stale stale bot closed this as completed Sep 13, 2019
@csebranek
Copy link

calendar.setOpen(true) works for me, but I still have to force typescript to ignore it other wise I get the error Property setOpen does not exist on type MutableRefObject<any> ?

@amemmes
Copy link

amemmes commented Jul 30, 2020

@cherner How did you get typescript to ignore it? I keep getting the error that setOpen is not an option. Thanks.

@csebranek
Copy link

csebranek commented Jul 30, 2020

@amemmes not recommended, but just place //@ts-ignore above the code

@amemmes
Copy link

amemmes commented Jul 30, 2020

Understood but it was the only way to get it to actually build and execute the setOpen function. Thanks for that.

@vietvu175
Copy link

vietvu175 commented Dec 23, 2020

There are no setOpen in ReactDatePickerProps.
To avoid ts warning:
const inputRef = useRef<ReactDatePickerProps & { setOpen:(open: boolean) => void }>(null);

@j-sup
Copy link

j-sup commented Dec 15, 2021

I'm a react/redux newb - so didn't immediately understand how the setOpen method might be exploited to wire up to redux.

Here's how I got the React parts to work for anyone else with same issue:

Create a ref to the calendar in your components constructor:

this.calendarRef = React.createRef();

Attach the ref to your calendar:

<DatePicker ref={this.calendarRef} />

Then you can use the ref to trigger the setOpen method:

<button onClick={() => {this.calendarRef.current.setOpen(true)}}>
  Open sesame
</button>

Thank you. How can this work with function components?

@david-jones10
Copy link

david-jones10 commented Jun 15, 2022

@j-sup I've just come across this, I've been able to get it working with a functional component as follows:

Create a ref to the calendar in the top level of the component, with the useRef() hook.
Pass this reference to the DatePicker component in the same way, as a ref prop.
Then trigger the open method in a similar manner, simply excluding the this. prefix.

Example:

const PickerWithButtonToOpen = () => {
  const calendarRef = React.useRef(); // or "import { useRef } from React" and simply useRef()

  return (
    <>
      <Datepicker ref={calendarRef} />
      <button onClick={() => calendarRef.current.setOpen(true)}>
        Open sesame
      </button>
    </>
  )
}

It would be good to have an open property to allow users to manage the popper display state outside of the component, rather than passing in a ref to the component though.

@gabrielmlinassi
Copy link

For me, to close the calendar, calendarRef.current.setOpen(false) didn't work. Had to do calendarRef.current.setState(prev => ({ ...prev, open: false })).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests