Skip to content

Can't createEvent* more than one event in loop #239

@tcowin

Description

@tcowin

Using the demo code in a loop, I can't create more than one(or two, sometimes) event. The second call to createEvent will issue a 'No calendar has been set." error(even though findEKCalendar has just printed "Calendar: Calendar" to the log). Trying more than 2, in general, results in nothing happening.

However, if I take the code in createEventWithOptions in Calendar.m out from behind the 'runInBackground' call,

/* [self.commandDelegate runInBackground: ^{ */

everything works perfectly, although a tad slower, obviously.

XCode 7.0.1
iOS 9.0.2
Cordova 5.3.1
"cordova-plugin-calendar": "4.4.3"

screen shot 2015-10-02 at 11 34 42 am

Activity

ants-house

ants-house commented on Feb 10, 2016

@ants-house

Hey,
I'm discovering the same issue on iOS... Creating one event works perfectly, creating more than one event ends up in freezing or just doin' nothing. The same issue is for deleting events. Deleting one event works, deleting more than one doesn't work. On Android everything works as expected, on iOS everything is broken. I also restricted creating events to max. 64.

/** Create a single event
 * @param eventToCreate
 */
var createEvent = function (eventToCreate) {

    function onSuccess (argument) { 
        console.log(TAG + "Event created: ", argument); 
    }

    function onError (argument) {
        console.error(TAG + "Failed to create event", argument);
    }

    $ionicPlatform.ready(function() {
        window.plugins.calendar.createEventWithOptions(eventToCreate.title,    eventToCreate.location, eventToCreate.shortdescription, parseDate(eventToCreate.start), parseDate(eventToCreate.end), calendarOptions, onSuccess, onError);
    });
};

/**
 * Create a list of events
 * @param eventsToCreate
 * @returns {promise}
 */
var createEvents = function (eventsToCreate) {

    var deferred = $q.defer();

    for (var i = 0; i < eventsToCreate.length && i < 64; i++) {
        createEvent(eventsToCreate[i]);

        if(i == eventsToCreate.length-1 || i == 63) {
            // return number of created events
            deferred.resolve(i + 1);
        }
    }

    //TEST: this works
    //createEvent(eventsToCreate[0]);
    //deferred.resolve(1);

    return deferred.promise;
};

Maybe someone can help... I really need this so a workaround would be better than nothing.

Regards

EddyVerbruggen

EddyVerbruggen commented on Feb 10, 2016

@EddyVerbruggen
Owner

Are you waiting for the first createEvent to return or are you just hammering the native code 64 times in a row?

ants-house

ants-house commented on Feb 10, 2016

@ants-house

Well I'm running through the for loop which always calls the native code. I think it's not waiting for the first createEvent to finish. Is there a possibility to wait for it?

tcowin

tcowin commented on Feb 10, 2016

@tcowin
Author

I did commit to fix this, but it’s not going to happen today. The problem is that it is not multithread safe. If you don’t run it in the background, then it will work fine in your context. You’d need to edit (hack cough, cough) src/ios/Calendar.m and comment out the loop that puts it in the background, like so:

in the function createEventWithOptions (lines 470 and 557 in the latest):

/* [self.commandDelegate runInBackground: ^{ */

/* }];*/

Thanks,

Tom

On Feb 10, 2016, at 7:42 AM, aaronprojects notifications@github.com wrote:

Well I'm running through the for loop which always calls the native code. I think it's not waiting for the first createEvent to finisch. Is there a possibility to wait for it?


Reply to this email directly or view it on GitHub #239 (comment).

ants-house

ants-house commented on Feb 10, 2016

@ants-house

Got it :)! Calling the function recursively works really good!

/**
 * Create a list of events
 * @param eventsToCreate
 * @returns {promise}
 */
var createEvents = function (eventsToCreate) {

    var deferred = $q.defer();

    var createSingleEvent = function (events, i) {

        function onSuccess (argument) {
            createSingleEvent(events, i+1);     
        }

        function onError (argument) {
            deferred.reject({ message: argument });
        }

        $ionicPlatform.ready(function() {
            if (i < events.length) {
                window.plugins.calendar.createEventWithOptions(events[i].title, events[i].location, events[i].shortdescription, parseDate(events[i].start), parseDate(events[i].end), calendarOptions, onSuccess, onError);
            } else {
                deferred.resolve(events.length);
            }
        });
    };

    createSingleEvent(eventsToCreate, 0);

    return deferred.promise;
};
EddyVerbruggen

EddyVerbruggen commented on Feb 10, 2016

@EddyVerbruggen
Owner

@aaronprojects That's the best way to do it as JS-Native calls to the Cordova bridge are async it's always best to wait for the callback to return.

Btw, by not running the Calendar in the background and hammering it in a loop you will block the UI which degrades performance.

tcowin

tcowin commented on Feb 10, 2016

@tcowin
Author

Of course - that’s just a temporary workaround.

Javascript is asynchronous for speed, right? So if you suggest you have to wait until every call completes whether or not you need the result, you’re losing the advantage that it gives you…

Actually this is just another way of working around the problem of it not being able to handle two addEvent calls in a row. It will still run O(N). I’d still think the best solution would be that it’s made multithread safe? I’ll try to figure it out.

On Feb 10, 2016, at 10:50 AM, Eddy Verbruggen notifications@github.com wrote:

@aaronprojects https://github.com/aaronprojects That's the best way to do it as JS-Native calls to the Cordova bridge are async it's always best to wait for the callback to return.

Btw, by not running the Calendar in the background and hammering it in a loop you will block the UI which degrades performance.


Reply to this email directly or view it on GitHub #239 (comment).

EddyVerbruggen

EddyVerbruggen commented on Feb 10, 2016

@EddyVerbruggen
Owner

@tcowin I know you did it is as a workaround / experiment, I'm just making sure others understand why it's implemented like it is.

I never created the plugin with threadsafeness in mind (that's why I added recurring events for making many events), but I can imagine there are valid cases for it. I don't know if whether or not the native calendar can be stressed that much so I'd rather not hammer it too much. Please consider that when trying to make it threadsafe and test it in a loop of 100+ invocations.

tcowin

tcowin commented on Feb 10, 2016

@tcowin
Author

Sure - will do. The app that uses this for us syncs a set of distinct events for the user's conference itinerary, so the recurring is not an option. I'll look at what it would take to enable concurrent calls to addEvent, but maybe adding a call like addEvents, where you'd send in an array of events that the Objective C then iterates through might even be more performant.

BhargavaNandan

BhargavaNandan commented on Jul 31, 2017

@BhargavaNandan

Hi this plugin is compatible with ios and android do we have any plugin to add calendar events for windows 10 devices using cordova

unsama

unsama commented on Dec 5, 2017

@unsama

**

> events: [
>                         {
>                             title: 'All Day Event',
>                             start: new Date(y, m, 1)
>                         },
>                         {
>                             id: 999,
>                             title: 'Repeating Event',
>                             start: new Date(y, m, d - 3, 16, 0),
>                             allDay: false,
>                             className: 'info'
>                         },
>                         {
>                             id: 999,
>                             title: 'Repeating Event',
>                             start: new Date(y, m, d + 4, 16, 0),
>                             allDay: false,
>                             className: 'info'
>                         },
>                         {
>                             title: 'Meeting',
>                             start: new Date(y, m, d, 10, 30),
>                             allDay: false,
>                             className: 'important'
>                         },
>                         {
>                             title: 'Lunch',
>                             start: new Date(y, m, d, 12, 0),
>                             end: new Date(y, m, d, 14, 0),
>                             allDay: false,
>                             className: 'important'
>                         },
>                         {
>                             title: 'Birthday Party',
>                             start: new Date(y, m, d + 1, 19, 0),
>                             end: new Date(y, m, d + 1, 22, 30),
>                             allDay: false,
>                         },
>                         {
>                             title: 'Click for Google',
>                             start: new Date(y, m, 28),
>                             end: new Date(y, m, 29),
>                             url: 'http://google.com/',
>                             className: 'success'
>                         }
>                     ],

**
here's my calendar events how i add in loop to post in database

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @tcowin@EddyVerbruggen@BhargavaNandan@ants-house@unsama

        Issue actions

          Can't createEvent* more than one event in loop · Issue #239 · EddyVerbruggen/Calendar-PhoneGap-Plugin