wix / react-native-calendars

React Native Calendar Components 🗓️ 📆
MIT License
9.52k stars 2.95k forks source link

Agenda: allow to scroll past the initial selected day? #80

Open slorber opened 7 years ago

slorber commented 7 years ago

Hi,

Thanks for this great project

Let's take the example agenda that is published on expo

The initial day is selected={'2017-05-16'}

The loading function is:

  loadItems(day) {
    setTimeout(() => {
      for (let i = -15; i < 85; i++) {
        const time = day.timestamp + i * 24 * 60 * 60 * 1000;
        // load items for that time
        // ...
      }
    }

To my understanding, the purpose of this function is to load new items data as the user is changing date or scrolling. It is also triggered initially on initial day.

In this demo, we can see the purpose of loading next 85 days, and previous 15 days.

Yet, even if 15 days before the initial day selected={'2017-05-16'} have been loaded in state, the UI does not allow to scroll back in time. The only way to browse items of a past day is to open the knob and select a date. In my app I don't want the knob so it means there's no easy way to access the past items.

I don't know what could be a good solution to this problem. I guess rendering items lazily at the top after mount would mess-up with scroll position. For me a good enough solution would be that every items provided on mount could be rendered initially, and for otherwise keep current behavior.

What do you think?

tautvilas commented 7 years ago

Hi, ideally I wanted to implement full scrolling backwards and forward, however there are RN limitations with such solution. There were some thoughts to make available past scrolling for preloaded period, but in order of consistency scrolling always stops on selected calendar date. Maybe this could be improved.

dongawli commented 7 years ago

I am too facing this issue. I've already loaded more than 500 items and still user needs to select date using knob to see the previous items. Any timeline for this enhancement? Thank you.

dborstelmann commented 7 years ago

Would really love this enhancement, please let us know if this is in the pipeline!

francescjimenez commented 7 years ago

Yes, we would also be very useful for our application

tautvilas commented 7 years ago

Sorry, but there are no short-term plans to solve this. There is some chance that it could be fixed this year though.

faridescate commented 7 years ago

+1

smkhalsa commented 7 years ago

+1

mirrorshades commented 7 years ago

+1

asantos00 commented 7 years ago

+1

asantos00 commented 7 years ago

Guys, I'm thinking about actually implementing this improvement, that's why I'm starting this discussion.

Do you guys think it makes sense to pass in openDate as a prop an into the calendarList component (that it will use to "center" the scroll) ?

tautvilas commented 7 years ago

Hi, could you elaborate? What is your proposed solution? Thx

francescjimenez commented 7 years ago

Of course i'm interested. I don't know if a solution would be to have a larger "pre-loaded" list and display or not display a row as needed.

I have created a day view similar to google calendar, with "swipe effect" and I used a "carrousel strategy". It would be another option... Always load the previous week, current and later, and only update the data

Nuptial commented 7 years ago

+1

dk0r commented 7 years ago

Is this <Agenda/> issue related to #187 (a <CalendarList/> issue) ?

peterpme commented 7 years ago

I believe https://facebook.github.io/react-native/docs/flatlist.html#initialscrollindex is how we can make this work. Work might make this a priority for me, stay tuned.

mkharibalaji commented 6 years ago

+1

YolandaQingniu commented 6 years ago

+1

chapeljuice commented 6 years ago

I, too, think this is a pretty huge feature. Makes so much sense. Would love if someone could make it happen!

AbdallaElabd commented 6 years ago

If you're incrementally loading data as the user scrolls up in the past, you'd be adding items to the top of the list, and that would mess up the scroll position. Bi-directional infinite scrolling is quite challenging.

peterpme commented 6 years ago

Moving forward:

Unless you have constructive feedback or a solution to give, please add a "THUMBS UP" to the original issue instead creating a comment with just +1

The extra comments are just noise for the contributors and will only slow them down.

Thanks!

chapeljuice commented 6 years ago

Personally I don't think infinite past scrolling is even needed.

If we could at least set a currentDate, then set pastScrollRange to any number, I would expect the calendar open up to the currentDate, but be able to scroll to x months previously until you get back to the pastScrollRange value.

Does that make sense? Is this a different request, or similar enough?

Ranatchai commented 6 years ago

To me the simple solution is that we could pass down renderHeader and renderFooter to the list (reservation-list component), so we can create components like LoadPrevItemButton and LoadNextItemButton to manage the infinite scroll.

geniuscd commented 6 years ago

I think this is related to this issue #259

chapeljuice commented 6 years ago

I feel like this is a very simple, yet crucial feature.

If we could at least set a currentDate, then set pastScrollRange to any number, I would expect the calendar open up to the currentDate, but be able to scroll to x months previously until you get back to the pastScrollRange value.

ptmt commented 6 years ago

For those who's interested in a very hacky solution when you at least have some amount of preload days I'm using this workaround:

const iso = date => date.format("YYYY-MM-DD");
const realInitialDate = iso(moment());
const pseudeInitialDate = iso(moment().add(-1, "week"));
...
 <Agenda 
       ref={r -> r.chooseDay(realInitialDate, true) } 
       selected={pseudeInitialDate} 
 />

If your views are heavy you may need to wait until the layout gets resolved before choosing a day.

cawfeecoder commented 6 years ago

@ptmt Doesn't work for me. I get an error about clone not being available.

DavitVosk commented 6 years ago

Has anyone solved the problem here?

YaoHuiJi commented 6 years ago

since this is the most commented open issue, I think it will be nice to add a description in the document to tell new user that the agenda is unidirectional.

ItsNoHax commented 6 years ago

Damn, this is the only thing stopping me from using this library in our production app :/

cawfeecoder commented 6 years ago

I ended up writing my own to fill my current production need.

On August 7, 2018 at 9:01:10 AM, Blanco Alberto (notifications@github.com) wrote:

Damn, this is the only thing stopping me from using this library in our production app :/

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/wix/react-native-calendars/issues/80#issuecomment-411047547, or mute the thread https://github.com/notifications/unsubscribe-auth/AKKvQcdX-DtLbx55E16hx0JgHhGW8kNrks5uOY-VgaJpZM4ONVIj .

victorsilent commented 6 years ago

@tautvilas can you explain more about those RN limitations?

apppro123 commented 5 years ago

Is there now any solution for scrolling in the past?

pmaduarte commented 5 years ago

Hello. Any news on this issue?

saigyouyou commented 5 years ago

@slorber

I have a simple way to solve it, though not perfect. Add a _onRefresh func in react-native-calendars/src/agenda/reservation-list/index.js

_onRefresh = () => {
  let h = 0;
  let scrollPosition = 0;
  const selectedDay = this.props.selectedDay.clone();
  const iterator = parseDate(this.props.selectedDay.clone().getTime()-3600*24*10*1000);
  let reservations = [];
  for (let i = 0; i < 10; i++) {
    const res = this.getReservationsForDay(iterator, this.props);
    if (res) {
      reservations = reservations.concat(res);
    }
    iterator.addDays(1);
  }
  scrollPosition = reservations.length;
  for (let i = 10; i < 30; i++) {
    const res = this.getReservationsForDay(iterator, this.props);
    if (res) {
      reservations = reservations.concat(res);
    }
    iterator.addDays(1);
  }
  this.setState({
    reservations
  }, () => {
    setTimeout(() => {
      let h = 0;
      for (let i = 0; i < scrollPosition; i++) {
        h += this.heights[i] || 0;
      }
      this.list.scrollToOffset({offset: h, animated: false});
      this.props.onDayChange(selectedDay, false);
    }, 100);
  });
}

And rewite the onRefresh in render()

<FlatList
  ...
  onRefresh={this._onRefresh}

then add a parmas in onDaychange func in react-native-calendars/src/agenda/index.js

onDayChange(day, f=true) {
  ...
  this.calendar.scrollToDay(day, this.calendarOffset(), withAnimation && f); //add f here
 ...

It works in the demo. If you want to use in your project, maybe you need change some parmas to fit your project.

faustinobsd commented 5 years ago

@saigyouyou Your solution is the best I found so far.

You've only missed one import. In react-native-calendars/src/agenda/reservation-list/index.js add:

import {parseDate} from '../../interface';

Thank you for this solution.

@slorber

I have a simple way to solve it, though not perfect. Add a _onRefresh func in react-native-calendars/src/agenda/reservation-list/index.js

erzhtor commented 4 years ago

I've also got stuck with this. Any updates so far?

ifeoluwak commented 3 years ago

Thank you, thank you @saigyouyou for this solution.

simon-musy commented 2 years ago

Is there any update on this topic? This is the best agenda library I've found out there although not being able to scroll past the selected date when the items are loaded is a little frustrating for the users. I've tried using @saigyouyou workaround to no success with the latest version (1.1277.0), in my case it just triggers the refresh functionality when attempting to scroll up.

hakan9719 commented 1 year ago

Still not change for Agenda...

wagnercsfilho commented 1 year ago

Any updates ?

maximilian commented 1 year ago

Unfortunately solution by @saigyouyou also doesn't work for me with latest version. Any ideas if a similar solution will be released?

sampitcher commented 1 week ago

in the _onRefresh function, change the.setState to:

    this.setState({
        reservations
      }, () => {
        setTimeout(() => {
          let h = 0;
          for (let i = 0; i < scrollPosition; i++) {
            h += this.heights[i] || 0;
          }
          if (this.list.current) {  // Ensure list reference exists
            this.list.current.scrollToOffset({ offset: h, animated: false });
          }
          this.props.onDayChange(selectedDay, false);
        }, 100);
      });