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

add support for changing years #52

Closed
terebentina opened this Issue Aug 11, 2015 · 24 comments

Comments

7 participants
@terebentina

terebentina commented Aug 11, 2015

It would be nice if we could switch the years somehow, without spamming the next/prev month links.
Either an extra pair of <</>> where the next/prev months are, or maybe a select box for years in the caption, or even a click on the caption to show an year sort of calendar (with just clickable years).
Something like:

| 2011 | 2012 | 2013 |
| 2014 | 2015 | 2016 |
| 2017 | 2018 | 2019 |
@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Aug 11, 2015

Owner

Hi this is not the first time I get this request ... I'm not sure how we should implement it. The example of the year calendar is an idea. How often enough would a user want to change the year? Could you provide some use case? :)

Owner

gpbl commented Aug 11, 2015

Hi this is not the first time I get this request ... I'm not sure how we should implement it. The example of the year calendar is an idea. How often enough would a user want to change the year? Could you provide some use case? :)

@terebentina

This comment has been minimized.

Show comment
Hide comment
@terebentina

terebentina Aug 11, 2015

In my app I need it to pick the year a friend was born and to add historic events (this day in history kind of trivia).

I can also see something like a resume building app where you pick the month+year for when you started/ended some job. If we default to today and the job started 5 years ago and ended 3 years ago it's going to be a real pain to add the 2 dates.

The year calendar idea could have an extra step:
You click on the normal calendar caption (August 2015) and you get a month calendar first:

| < ____ 2015 ____  > |
| Jan  | Feb | Mar | Apr |
| May | Jun | Jul  | Aug |
| Sep | Oct | Nov | Dec |

and then, clicking on the 2015 caption, you get the year calendar:

| < ____________ > |
| 2011 | 2012 | 2013 |
| 2014 | 2015 | 2016 |
| 2017 | 2018 | 2019 |

terebentina commented Aug 11, 2015

In my app I need it to pick the year a friend was born and to add historic events (this day in history kind of trivia).

I can also see something like a resume building app where you pick the month+year for when you started/ended some job. If we default to today and the job started 5 years ago and ended 3 years ago it's going to be a real pain to add the 2 dates.

The year calendar idea could have an extra step:
You click on the normal calendar caption (August 2015) and you get a month calendar first:

| < ____ 2015 ____  > |
| Jan  | Feb | Mar | Apr |
| May | Jun | Jul  | Aug |
| Sep | Oct | Nov | Dec |

and then, clicking on the 2015 caption, you get the year calendar:

| < ____________ > |
| 2011 | 2012 | 2013 |
| 2014 | 2015 | 2016 |
| 2017 | 2018 | 2019 |
@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Aug 12, 2015

Owner

Hi @terebentina, I believe I've seen this UI pattern already in another date picker, however I don't like it in terms of usability 😌

In your case, for example, you may better provide three day/month/year selects and use perhaps the day-picker as an aid to select the day. A date picker is not the only nor the best way to input a date, and I'd like to avoid complex solutions that don't provide good usability. What do you think?

Owner

gpbl commented Aug 12, 2015

Hi @terebentina, I believe I've seen this UI pattern already in another date picker, however I don't like it in terms of usability 😌

In your case, for example, you may better provide three day/month/year selects and use perhaps the day-picker as an aid to select the day. A date picker is not the only nor the best way to input a date, and I'd like to avoid complex solutions that don't provide good usability. What do you think?

@terebentina

This comment has been minimized.

Show comment
Hide comment
@terebentina

terebentina Aug 12, 2015

Ughh, selects...and 3 of them? Yuck! :)
In general, I think picking a date should be ...umm...an atomic action. Or, in other words, when I decided on a date, all 3 components (day, month, year) should be set at once. This way, the value I have for the date is either null/undefined or a valid date.
With 3 separate selects there's the risk of picking, say, 31 February so I'd need validation and a way to display these errors. It would be smart of me to abstract this away into a <ThreeSelectDayPicker /> component so it only sends the full date to my app. But with selects I'd also need a 'Save' button. This already sounds like a date picker alright, only with a worse UX (imho).

How about this:
You already have the showMonth() and onCaptionClick() methods. How about adding showYear() which would render the months of the current year as in my example above? You don't have to link the clicking on caption to showYear, you can leave this to the developer. If clicking on the caption isn't desired for this, they could implement it in a different place, but they'd still have the option.
Similarly you could have a showDecade().

Not sure about your concerns regarding usability...I am a windows & android user and on both the calendar is pretty much using this pattern. Maybe I got used to it...

terebentina commented Aug 12, 2015

Ughh, selects...and 3 of them? Yuck! :)
In general, I think picking a date should be ...umm...an atomic action. Or, in other words, when I decided on a date, all 3 components (day, month, year) should be set at once. This way, the value I have for the date is either null/undefined or a valid date.
With 3 separate selects there's the risk of picking, say, 31 February so I'd need validation and a way to display these errors. It would be smart of me to abstract this away into a <ThreeSelectDayPicker /> component so it only sends the full date to my app. But with selects I'd also need a 'Save' button. This already sounds like a date picker alright, only with a worse UX (imho).

How about this:
You already have the showMonth() and onCaptionClick() methods. How about adding showYear() which would render the months of the current year as in my example above? You don't have to link the clicking on caption to showYear, you can leave this to the developer. If clicking on the caption isn't desired for this, they could implement it in a different place, but they'd still have the option.
Similarly you could have a showDecade().

Not sure about your concerns regarding usability...I am a windows & android user and on both the calendar is pretty much using this pattern. Maybe I got used to it...

@TomGallon

This comment has been minimized.

Show comment
Hide comment
@TomGallon

TomGallon Sep 2, 2015

Hi

👍 We need it.

A common simple use case would be to select a birth date.

Regards,

TomGallon commented Sep 2, 2015

Hi

👍 We need it.

A common simple use case would be to select a birth date.

Regards,

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Sep 2, 2015

Owner

To be honest I believe this is not the component you are looking for: date pickers like these help to identify a day inside a month (e.g. by looking to its weekday), or to select a range, or to understand which days are "enabled" or not. How should the weekday help the user? "Yes, it must be this day because i was born on Sunday"? Selects or even text fields (maybe with type="date") work much better for such use cases.

In particular this one is called day-picker because it was born to select a day, not a month or even a year :-) Adding the ability to select month/year implies a lot of work: layout, styling, unit tests, keyboard navigation... if it's not worth it we have no reason to make this component more complex.

I'd like however to see some good implementations including this feature.

Owner

gpbl commented Sep 2, 2015

To be honest I believe this is not the component you are looking for: date pickers like these help to identify a day inside a month (e.g. by looking to its weekday), or to select a range, or to understand which days are "enabled" or not. How should the weekday help the user? "Yes, it must be this day because i was born on Sunday"? Selects or even text fields (maybe with type="date") work much better for such use cases.

In particular this one is called day-picker because it was born to select a day, not a month or even a year :-) Adding the ability to select month/year implies a lot of work: layout, styling, unit tests, keyboard navigation... if it's not worth it we have no reason to make this component more complex.

I'd like however to see some good implementations including this feature.

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Sep 2, 2015

Owner

(There is however a onCaptionClick prop that you can use to display a custom month/year selector, e.g. with a layer over the navigation bar)

Owner

gpbl commented Sep 2, 2015

(There is however a onCaptionClick prop that you can use to display a custom month/year selector, e.g. with a layer over the navigation bar)

@gnrlbzik

This comment has been minimized.

Show comment
Hide comment
@gnrlbzik

gnrlbzik Oct 14, 2015

@gpbl, i really like your date picker. But i will have to layer it up with year/month selection as well in my case. It seems like most date pickers require this functionality no matter if you agree with user experience or not.

gnrlbzik commented Oct 14, 2015

@gpbl, i really like your date picker. But i will have to layer it up with year/month selection as well in my case. It seems like most date pickers require this functionality no matter if you agree with user experience or not.

@JKillian

This comment has been minimized.

Show comment
Hide comment
@JKillian

JKillian Nov 12, 2015

Contributor

I understand where you're coming from @gpbl, but I agree that a faster way to change months/years would be good. I think the challenge here is making a good design. And I wonder if it's possible to fit in nicely with this component or not.

Just for the sake of discussion, you can try this link out in Chrome to see how they do date selection: http://jsfiddle.net/mhmq3mkz/.

Contributor

JKillian commented Nov 12, 2015

I understand where you're coming from @gpbl, but I agree that a faster way to change months/years would be good. I think the challenge here is making a good design. And I wonder if it's possible to fit in nicely with this component or not.

Just for the sake of discussion, you can try this link out in Chrome to see how they do date selection: http://jsfiddle.net/mhmq3mkz/.

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 13, 2015

Owner

Very interesting @JKillian, browsing the internet I've never used a date picker like that. I believe the amount of work for doing something like that is not worth it.

Wouldn't be a better design to show two <select>s when clicking the month caption, e.g.:

screen shot 2015-11-13 at 08 57 46

Owner

gpbl commented Nov 13, 2015

Very interesting @JKillian, browsing the internet I've never used a date picker like that. I believe the amount of work for doing something like that is not worth it.

Wouldn't be a better design to show two <select>s when clicking the month caption, e.g.:

screen shot 2015-11-13 at 08 57 46

@terebentina

This comment has been minimized.

Show comment
Hide comment
@terebentina

terebentina Nov 13, 2015

@gpbl your example is certainly acceptable for me.
I am not sure about < and > at the same time with the 2 selects though because then it would raise the need for << and >> and it looks crammed anyway.

terebentina commented Nov 13, 2015

@gpbl your example is certainly acceptable for me.
I am not sure about < and > at the same time with the 2 selects though because then it would raise the need for << and >> and it looks crammed anyway.

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 15, 2015

Owner

So maybe we have found a solution 🙌

But when should we make the selects disappear? I'm thinking to remove the < and > buttons, and add a button to go back to the previous view (I wouldn't put a button with a label Close because i18n).

Owner

gpbl commented Nov 15, 2015

So maybe we have found a solution 🙌

But when should we make the selects disappear? I'm thinking to remove the < and > buttons, and add a button to go back to the previous view (I wouldn't put a button with a label Close because i18n).

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 15, 2015

Owner

Example with close button:
screen shot 2015-11-15 at 11 32 33

Owner

gpbl commented Nov 15, 2015

Example with close button:
screen shot 2015-11-15 at 11 32 33

@terebentina

This comment has been minimized.

Show comment
Hide comment
@terebentina

terebentina Nov 15, 2015

Not very related to this issue but since you brought close into discussion, there are 2 more buttons that I miss, besides close: today and clear. Clear being for clearing the input which holds the date. I suppose clear could call onDayClick with null instead of a day.
Today is self-explanatory.
I think close should be toggle-able (in case someone doesn't want to close the picker but have it always visible) and in this case so should be the other 2 should you chose to implement them. It's not complicated for us to create a wrapper around react-day-picker to provide these buttons but I feel they belong with your picker rather than being external.

Regarding i18n you could add closeLabel/todayLabel/clearLabel as props to react-day-picker with English defaults.

And showing/hiding selects could be done with props like selectMonths/selectYears, no?

terebentina commented Nov 15, 2015

Not very related to this issue but since you brought close into discussion, there are 2 more buttons that I miss, besides close: today and clear. Clear being for clearing the input which holds the date. I suppose clear could call onDayClick with null instead of a day.
Today is self-explanatory.
I think close should be toggle-able (in case someone doesn't want to close the picker but have it always visible) and in this case so should be the other 2 should you chose to implement them. It's not complicated for us to create a wrapper around react-day-picker to provide these buttons but I feel they belong with your picker rather than being external.

Regarding i18n you could add closeLabel/todayLabel/clearLabel as props to react-day-picker with English defaults.

And showing/hiding selects could be done with props like selectMonths/selectYears, no?

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 15, 2015

Owner

@terebentina thanks for the sharing your ideas – those features are unlikely to be implemented since they are restricted to particular use cases. As you say, it's not hard to wrap the DayPicker inside a component, and I'd prefer the developer to follow this way instead of adding lot of new props to it.

Anyway I was thinking about the form pictured above, so this is how I'd implement it.

First I create the <form> component:

function YearMonthForm({ currentDate, onChange, onSubmit }) {

  const years = [2010, 2011, 2012, 2013, 2014, 2015];
  const months = dateUtils.getMonths();

  const currentMonth = currentDate.getMonth();
  const currentYear = currentDate.getFullYear();

  const handleChange = function(e) {
    onChange(new Date(e.target.form.year.value, e.target.form.month.value));
  }

  return (

    <form onSubmit={ onSubmit }>
      <select name="month" onChange={ handleChange }>
        { 
          months.map( (month, i) => 
            <option key={i} value={i} selected={ currentMonth === month}>
              {month}
            </option>
          ) 
        }
      </select>

      <select name="year" onChange={ handleChange }>
        { 
          years.map( (year, i) => 
            <option key={i} value={year} selected={ currentYear === year}>
              {year}
            </option>
          ) 
        }
      </select>
      <button type="submit">OK</button>

    </form>
  )
}

In a DayPicker implementation, I'd pass it to a new captionNode prop when the user clicks on the caption:

class MyComponent extends React.Component {

  state = {
    canChangeYear: false,
    selectedDay: new Date()
  }

  render() {
    const { canChangeYear, selectedDay } = this.state;

    return (
      <DayPicker 
        ref="daypicker"
        canChangeMonth={ !canChangeYear }
        onDayClick={ (e, day) => this.setState({ selectedDay: day }) }
        onCaptionClick={ () => this.setState({ canChangeYear: true }) }
        captionNode ={ canChangeYear &&
          <YearMonthForm currentDate={ selectedDay } 
            onChange={ month => this.refs.daypicker.showMonth(month) } 
            onSubmit={ () => this.setState({ canChangeYear: false }) }/>
        } 
      />
    )
  }
}

If not null, the new captionNode prop would render a custom caption instead of the standard MONTH YEAR text. By setting canChangeMonth to false, we would prevent the user's navigation between the days.

I like this approach because the interaction between form and DayPicker is left to the developer (e.g. he could attach some events on the select elements, disable months for specific times, etc).

Owner

gpbl commented Nov 15, 2015

@terebentina thanks for the sharing your ideas – those features are unlikely to be implemented since they are restricted to particular use cases. As you say, it's not hard to wrap the DayPicker inside a component, and I'd prefer the developer to follow this way instead of adding lot of new props to it.

Anyway I was thinking about the form pictured above, so this is how I'd implement it.

First I create the <form> component:

function YearMonthForm({ currentDate, onChange, onSubmit }) {

  const years = [2010, 2011, 2012, 2013, 2014, 2015];
  const months = dateUtils.getMonths();

  const currentMonth = currentDate.getMonth();
  const currentYear = currentDate.getFullYear();

  const handleChange = function(e) {
    onChange(new Date(e.target.form.year.value, e.target.form.month.value));
  }

  return (

    <form onSubmit={ onSubmit }>
      <select name="month" onChange={ handleChange }>
        { 
          months.map( (month, i) => 
            <option key={i} value={i} selected={ currentMonth === month}>
              {month}
            </option>
          ) 
        }
      </select>

      <select name="year" onChange={ handleChange }>
        { 
          years.map( (year, i) => 
            <option key={i} value={year} selected={ currentYear === year}>
              {year}
            </option>
          ) 
        }
      </select>
      <button type="submit">OK</button>

    </form>
  )
}

In a DayPicker implementation, I'd pass it to a new captionNode prop when the user clicks on the caption:

class MyComponent extends React.Component {

  state = {
    canChangeYear: false,
    selectedDay: new Date()
  }

  render() {
    const { canChangeYear, selectedDay } = this.state;

    return (
      <DayPicker 
        ref="daypicker"
        canChangeMonth={ !canChangeYear }
        onDayClick={ (e, day) => this.setState({ selectedDay: day }) }
        onCaptionClick={ () => this.setState({ canChangeYear: true }) }
        captionNode ={ canChangeYear &&
          <YearMonthForm currentDate={ selectedDay } 
            onChange={ month => this.refs.daypicker.showMonth(month) } 
            onSubmit={ () => this.setState({ canChangeYear: false }) }/>
        } 
      />
    )
  }
}

If not null, the new captionNode prop would render a custom caption instead of the standard MONTH YEAR text. By setting canChangeMonth to false, we would prevent the user's navigation between the days.

I like this approach because the interaction between form and DayPicker is left to the developer (e.g. he could attach some events on the select elements, disable months for specific times, etc).

@JKillian

This comment has been minimized.

Show comment
Hide comment
@JKillian

JKillian Nov 15, 2015

Contributor

@gpbl I like this approach with the new captionNode prop. Then people could choose if they wanted the version with only the < and > buttons, or if they wanted the version with selects. (And you could implement whichever you want as the default.)

Contributor

JKillian commented Nov 15, 2015

@gpbl I like this approach with the new captionNode prop. Then people could choose if they wanted the version with only the < and > buttons, or if they wanted the version with selects. (And you could implement whichever you want as the default.)

@adidahiya

This comment has been minimized.

Show comment
Hide comment
@adidahiya

adidahiya Nov 19, 2015

Contributor

+1 switching month / year quickly is pretty important to me in a datepicker component. If I can get that functionality quicker via #88 rather than via the suggestions in this thread, then I'd advocate for implementing #88 first.

Contributor

adidahiya commented Nov 19, 2015

+1 switching month / year quickly is pretty important to me in a datepicker component. If I can get that functionality quicker via #88 rather than via the suggestions in this thread, then I'd advocate for implementing #88 first.

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 24, 2015

Owner

Wordpress could implement the day picker with support for changing years. This is also an interesting approach:
untitled

Owner

gpbl commented Nov 24, 2015

Wordpress could implement the day picker with support for changing years. This is also an interesting approach:
untitled

@adidahiya

This comment has been minimized.

Show comment
Hide comment
@adidahiya

adidahiya Nov 24, 2015

Contributor

@gpbl not really a fan of that approach because it still requires a lot of clicks to quickly move around in time (try going to 1970...)

Contributor

adidahiya commented Nov 24, 2015

@gpbl not really a fan of that approach because it still requires a lot of clicks to quickly move around in time (try going to 1970...)

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Nov 24, 2015

Owner

@adidahiya I'm working on an example with the select elements, using a new captionElement prop:

months

Owner

gpbl commented Nov 24, 2015

@adidahiya I'm working on an example with the select elements, using a new captionElement prop:

months

gpbl added a commit that referenced this issue Nov 24, 2015

@adidahiya

This comment has been minimized.

Show comment
Hide comment
@adidahiya

adidahiya Nov 24, 2015

Contributor

@gpbl nice! we'll try this out soon, likely next week

Contributor

adidahiya commented Nov 24, 2015

@gpbl nice! we'll try this out soon, likely next week

@gpbl

This comment has been minimized.

Show comment
Hide comment
@gpbl

gpbl Dec 4, 2015

Owner

With the new captionElement prop introduced in v1.2.0 you can now add your custom navigation between months (or years). See this example using a form to change months/years.

PS. @adambbecker perhaps this change is interesting to you? I've seen Calypso implementing a navigation between years in the date picker, I guess with some CSS positioning workaround.

Owner

gpbl commented Dec 4, 2015

With the new captionElement prop introduced in v1.2.0 you can now add your custom navigation between months (or years). See this example using a form to change months/years.

PS. @adambbecker perhaps this change is interesting to you? I've seen Calypso implementing a navigation between years in the date picker, I guess with some CSS positioning workaround.

@gpbl gpbl closed this Dec 4, 2015

@JKillian

This comment has been minimized.

Show comment
Hide comment
@JKillian

JKillian Dec 4, 2015

Contributor

Using the new captionElement prop now - it's working great! Much better than the hacky workarounds of the past 😄 Thanks for the update/release.

Contributor

JKillian commented Dec 4, 2015

Using the new captionElement prop now - it's working great! Much better than the hacky workarounds of the past 😄 Thanks for the update/release.

@adambbecker

This comment has been minimized.

Show comment
Hide comment
@adambbecker

adambbecker Dec 6, 2015

Contributor

Oh nice! Thanks @gpbl for the heads up, this will certainly prove quite useful and a much more elegant solution.

Contributor

adambbecker commented Dec 6, 2015

Oh nice! Thanks @gpbl for the heads up, this will certainly prove quite useful and a much more elegant solution.

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