ui-calendar
ui-calendar copied to clipboard
Calendar is awfully slow when loading lots of events
When inserting lots of elements the performance of UI-calendar is far FAR inferior than default Fullcalendar.
In my case when a user loads his profile it may have more than 500 events, in default JS Fullcalendar the insertion is almost instantaneous, using UI-calendar it takes minutes (and more than just a couple). This simple use case shows that using your calendar it's almost impossible when dealing with lots of events, in addition to that the time taken grows more than linearly for every event added to the set.
The main problem is the angular deep watching of what you called "tokens". For now I'll have to switch back to vanilla Fullcalendar since this performance issue cannot be solved with just a few tweeks but would require a complete rewrite of the directive.
I can only give a simple advice for now: don't rely on the automatic update based on model watching, try some other way!
EDIT: I've tried to change some of your code and now it's faster, anyway it's also a Fullcalendar issue having something to do with moment (wasn't there in 1.6.7 but it's really noticeable in 2.x)
Care to elaborate about the changes made?
I don't think they could fit in such a general purpose plugin like yours and since I had not such great improoves in speed I simply thrown them away using a workaround.
Now let's get to the code stuff:
- since I didn't care about changes in event properties I used watchCollection instead of the deep watch you're using to see if there where changes in the events
- if watchColection triggers I divided the logic trying to know if there where adds or removes in events at first the using lodash (difference for example) to quickly calculate which events had to be removed and which had to be added
- the logic to watch event sources was different than that of watching events since there is no need to do more complex operations to know if a source was added or removed Even removing complexity speed was still a huge issue so maybe it was not the deep watching the bottleneck. Inspecting the CPU usage I realized it was fullcalendar the problem.
Then I tried adding a function as event source but it was giving me errors (didn't bothered to know why since I'm in a big hurry for the coming week) so I ended up using the events property inside calendar options to grab data directly from the backend and watching the events I get back for changes before they are passed to fullcalendar and everything is smoooooth now.
So I thought to myself that maybe you should in work in a different direction... just give me the time to finish the project I'm working on and I'll have more time to discuss my findings and maybe share some code! Il 25/feb/2015 19:38 "Farid" [email protected] ha scritto:
Care to elaborate about the changes made?
— Reply to this email directly or view it on GitHub https://github.com/angular-ui/ui-calendar/issues/232#issuecomment-76026589 .
Just to give you a hint: the function that works perfectly when passed to fullcalendar was the one giving me errors when passed as event source... but code speaks louder than words, there are some real concept changes that must be made and try to explain myself via the forum would take more time than writing the directive! I'll keep in touch :)
I'm not a maintainer, just someone that likes to see these issues fixed :) But thanks anyway.
+1 this issue..
I'm trying to understand too, but it seems eventRender callbacks are called way too much times. For example I have 25 events on a month calendar, the eventRender callback is called 25 times on fullcalendar alone but 325 times with angular-ui-calendar ...
Warning: Workaround
Apparently, it's caused when trying to fill the event array when it's already assigned to the eventSources object. Assign it when it's already filled. See example:
on controller initialization:
$scope.eventSources = [];
in the refresh function, first fetch and fill $scope.Events, then:
uiCalendarConfig.calendars.eventCal.fullCalendar('removeEventSource', $scope.Events);
$scope.eventSources.push($scope.Events);
Thanks That work but I finally totally removed this angular plugin to use directly the jquery plugin.. In the end, it works like a charm now ^^
I am the author of the original watcher. I am pretty sure this would be fixed by #77, but it's been a year so the PR needs a rebase. I won't be working on any app using it this quarter, so someone else would need to the rebase. See also discussion in #21. Plunkr with the fix applied (against a year-old version of ui-calendar): http://plnkr.co/edit/af8v02?p=preview.
This should be fixed in the latest version. Can you guys comment here and we can close this issue out?
I am using the latest version and still the same issue with eventRender beeing called way to many times. Is there a better workaround then removing the eventsources everytime events are loading?
can you give an example please? Here is an example of many events working with the latest code. Its pretty fast. http://plnkr.co/edit/GBNxiZ?p=preview
Well the thing is I am loading every month a couple of hundred events. So I am adding to the eventsource everytime a new month is clicked. So evertime events are added eventRender is called about 1000 to 3000 times. If I return to an allready loaded month eventRender is called as many times as events are currently shown in the selected month. So this is working. Problem is adding events to the eventsource. So kind of what the issue is all about if i understood it right. I hope my explanation is understandable. I am using fullcalendar version 2.3.1, angularjs version 1.4.0-rc.1 but its the same with version 1.2.28 and ui-calendar version 1.0.0 Help would be awesome. Thanks for your effort and thanks for your awesome work with ui-calendar. kind regards Thomas
@joshkurz nice, thank you! Can I updated via bower?
Well I did some more testing. Even if I push all my eventSources after they have been filled into my calendar event Source array. EventRender gets called 1000 times. I am using an Array of arrays as my eventSource! could that be the trouble? kind regards Thomas
Anybody anymore suggestions on how to solve this issue? Regards Thomas
Maybe this post can help you guys http://stackoverflow.com/questions/1924336/jquery-fullcalendar-fetch-event-optimization
+1 I need to display in the calendar about 2000 events. For each of them I also need to generate a tooltip. Currently, it tooks more than a 2 minuts and a half to create the whole calendar... After I limited the calendar to the previous, present, and next month it still takes more than half a minute.
I've used all of the solution that have been suggested in this topic but the calendar is still awfully slow...
I had a similar problem. My solution was to forcibly change the sourcesChanged variable in the uiCalendar directive to true. The eventsSourceWatcher is looking for changes to the sourcesChanged variable. Changing sourcesChanged to true causes the calendar to render all the events once, instead of calling onAdded on each event, which is causing the slow down.
I added my own 'reinit' property to the uiCalendar directive scope and set up a watcher to watch for changes to that property. A separate controller in my app that is responsible for updating the calendar sources changes the reinit property when the calendar sources change. When the reinit property is changed then the sourcesChanged property is changed to true and the calendar is re-rendered. It ain't pretty but it works.
Hi Joe, Could you please provide some sample code of your solution? I was trying to replicate it (in a simpler way). In calendar.js I've changed the eventSourcesWatcher function:
eventSourcesWatcher.onAdded = function(source) { calendar.fullCalendar('addEventSource', source); sourcesChanged = false; };
then in the main file I've written something like this:
$scope.uiConfig = { calendar: { width: 800, height: 950, editable: false, header: { left: 'prev,next, today', center: 'title', right: 'month,basicWeek,basicDay' }, eventClick: $scope.openWindowOnEventClick, eventRender: $scope.eventRender, sourcesChanged: false } };
$scope.makeCalendar = function() {
$scope.eventSources.push($scope.loadAdditionalEvents());
$scope.uiConfig.sourcesChanged = true;
}
$scope.makeCalendar();
It works but still is awfully slow...
you can try using ('addEventSource', events) with events is an array that contains all your events, it speed up the rendering.
Thanks @ryadiv ! .. Before use addEventSource my browser freezes with 200 events and, after use it, I can load more than 1,500 events without problem :-)
It seems like I can only choose one or the other: render the events quickly, or have the calendar watch for changes on each event. Is this true, or do I have a configuration problem? I'm having trouble doing both:
$scope.calendar = { eventSources: [{events: listOfEvents}] }
and in the HTML template:
ui-calendar="calendar.config"
ng-model="calendar.eventSources"
calendar="myCalendar"
calendar-watch-event="checkEvent(event)"
If I want to watch every event, with more than a few hundred events, a browser lock occurs because onAdded
is triggered, which renders each event individually. I think that ideally, the behaviour I'd like to have is for the calendar to render all of the events instead of each individually. Then, watch for changes on each event.
Currently, I can render all the events very quickly, but not watch for changes on them, OR I can watch for changes on the events, but will result in browser lock with a few hundred events.
@giovannibenussi how did u solve your problem? im having the same issue, and i'm using:
$('#calendar').fullCalendar('addEventSource',"events.php");
but it didn´t work, is still very slow. Please help. Thanks!!
@giovannibenussi do you have a code snippet to share on how you got to addEventSource event?
Hi - is there any updates to this ? also have the problem with Fullcalendar loading with 10-20 seconds loadtime. There is many entries.
Is it possible to have it display entries one by one as they are loading ?
I see this issue is still open, after 2 years.
Any way I captured some interesting results from eventRender....
When 1 event exists on the day eventRender is called once. (1 + 0) When 2 events exist eventRender is called 3 times. (2 + 1) When 3 events exist eventRender is called 5 times. (3 + 2) 4 events cause it to fire 7 times. (4 + 3) etc. And its cumulative, adds on as if looping and adding and looping and adding.
It seems to execute eventRender more times than there are events on the day by adding to the count of times it fires based on the previous count.
This is extremely time consuming when you have 100+ events to render.
For example in my testing, 38 events caused eventRender to fire a total of 741 times....Anyone figured out a solution or why its doing this??
Hey MartinCarlson, sorry for the late reply!
I was able to speed things up dramatically by passing in uiCalendarConfig to the controller the page was running from. Then I used:
uiCalendarConfig.calendars.myCalendar1.fullCalendar('addEventSource', [events]);
As you might be able to see, I was insanely imaginative and called my calendar 'myCalendar1'. Using the snippet above, and the uiCalendarConfig service that I passed in I could access my calendar. That then has the full jQuery fullCalendar object. This will give you access to many of the methods that are available. The addEventSource method increased the load time but about a hundred million percent for me. There are other methods I could use like 'removeEvents', 'refectEvents' and 'gotoDate'
Hope this helps!
@nlaycock no problem. Thanks for replying, I did make use of the addEventSource method and my word loading times were crazy fast. That should definitely be highlighted as the go to way to get events onto the calendar.
Thanks!