0

I'm using ui-calendar to display events. To fill out the calendar model, the controller fetches the events from a Factory. The wierd part (which I can't figure out), is that when the Factory fetches the data from the API, the calendar shows the events just fine. However, in order to "speed things up" a little, the Factory saves the api fetched data in a local variable. If the Factory returns the data from the local variable, the calendar does not display the events. However if the Factory returns data from the API, the events are displayed just fine (so there must be something wrong with the way I am returning the local variable data from the Factory).

The Factory method is as follows:

function getAll() {
    if (!_allEventsRequiresUpdate && _allEvents) {
        var deferred = $q.defer();
        deferred.resolve(_allEvents);
        return deferred.promise;
    }
    else {
        var request = $http({
            method: "Get",
            url: baseUrl
        });
        return request.then(function (response) {
            _allEvents = response.data;
            _allEventsRequiresUpdate = false;
            return response.data;
        }, handleError);
    }

}

The _allEvents variable get filled when the data is fetched from the API. The data in both cases (returned from the API or the local variable), is exactly the same (at least to my knowledge), however, as stated previously, only the data fetched from the API gets rendered in ui-calendar/fullcalendar.

Any ideas? Is there something wrong as to how I am returning the local variable from the Factory?

BTW, in both cases, the controller resolves the promise.

UPDATE

The following is the method in the Angular controller that fetches the data from the Factory:

function getAllEvents() {
    serviceAppointmentsServices.getAll()
        .then(function (data) {
            vm.events = angular.copy(data);
            vm.fullCalendarEvents = [];

            for (var i = 0; i < vm.events.length; i++) {
                var event = {
                    id: vm.events[i].xrmId,
                    title: vm.events[i].xrmName,
                    start: moment(vm.events[i].startDate).tz('America/Santiago'),
                    end: moment(vm.events[i].endDate).tz('America/Santiago'),
                    stick: true
                }
                if (vm.events[i].xrmStatus.value == 1)
                    event.color = '#D2A15D';
                vm.fullCalendarEvents.push(event);
            }

            uiCalendarConfig.calendars["calendar"].fullCalendar('removeEventSources');
            uiCalendarConfig.calendars["calendar"].fullCalendar('addEventSource', vm.fullCalendarEvents);

        }, function (mesage) {
            toastr.error(mesage, "error!");
        });
}

Here is the calendar config:

vm.uiConfig = {
    calendar: {
        height: 450,
        editable: true,
        eventClick: editEvent,
        dayClick: addEvent,
        eventDrop: $scope.alertOnDrop,
        eventResize: $scope.alertOnResize,
        eventAfterAllRender: documentReady,
        locale: 'es',
        timezone: 'America/Santiago',
        customButtons: {
            addEvents: {
                text: 'nuevo',
                click: function () {
                    vm.fx.addEvent();
                    $scope.$apply()
                }
            }
        },
        header: {
            left: 'month basicWeek basicDay agendaWeek agendaDay',
            center: 'title',
            right: 'addEvents today prev,next'
        },
        eventRender: eventRender

    }
};
Nimantha
  • 6,405
  • 6
  • 28
  • 69
aplon
  • 445
  • 6
  • 24
  • can you show how this method is integrated with fullCalendar? And why do you need this method to "speed things up a little"? What exactly is being cached? Events for a wider time period than is initially required? Under what circumstances does it decide to use the "cached" data? – ADyson May 02 '17 at 09:50
  • The Factory method fetches the data from Dynamics CRM, which depending on the amount of events, it can take quite a while. So the first time I get the events from CRM, I store them in the factory's local variable. the second time the user goes to the events calendar, the data is already stored in the local variable, so no need to go to CRM again to fetch it. And of course, each time the user inserts, updates or deletes events, the factory's `_allEventsRequiresUpdate` is set to false, so events are fetched from CRM again. – aplon May 02 '17 at 10:21
  • but the only time the events need fetching again is a) if the view and/or displayed date changes, or b) you explicitly tell the calendar to re-fetch the events. b) is usually unnecessary, unless, when saving a new event to the server, you add some data to the event server-side which is not known on the client. In scenario a) your query should only be returning the events for the time period being displayed (fullCalender supplies the start/end dates), meaning a re-fetch is necessary each time the view changes, but that each set of retrieved events is small, hopefully reducing the query time. – ADyson May 02 '17 at 10:24
  • However... I can't be sure without seeing your actual fullCalendar config, but it seems like maybe you've decoupled the refresh of the events from the fullCalendar system? E.g. Why are you having to add/remove an event source each time? It shouldn't be necessary if you define the event source as a JSON feed as per the docs. If you really want to force an update outside the normal "date/view changing" context, you could then just call the "refetchEvents" method. – ADyson May 02 '17 at 10:27
  • You are totally right. The reason I am saving the events int the local variable, is in case the user tries to insert or update an event (different view and controller) and then cancels, and goes back to the events calendar. In this case, there is no need to fetch the events from CRM (which can take several seconds, even for a small amount of events) as no changes occured. – aplon May 02 '17 at 11:09
  • I finally used the add/remove event sources, as I have been unable to créate the object as is required (no events get displayed). I haven't tried the json feed path, so I'll start with that. – aplon May 02 '17 at 11:11
  • If you use the "events as a function" option (https://fullcalendar.io/docs/event_data/events_function/) you could probably integrate your "caching" model into it as well. Incidentally, have you set any breakpoints/logging to determine whether `_allEvents` is populated correctly when you return it as a "cached" object? Presumably it's empty? In which case, you have to determine at what point it gets cleared - maybe its scope is not sufficiently broad and the object is destroyed? – ADyson May 02 '17 at 11:14
  • That's precisely the strange beaviour. I set breakpoints both at the Factory and the controller. `_allEvents` has the same events as the fetched data from CRM. In the controller promise resolve (after the then), `data` has the events. But even so the events won't get rendered. – aplon May 02 '17 at 11:18
  • does `vm.fullCalendarEvents` subsequently contain the right events? Any error in the console at this time? – ADyson May 02 '17 at 11:28
  • vm.fullCalendarEvents has the correct data in both scenarios. I did a json compare of the objects returned by the service, comparing the object returned by the CRM fetch and the local variable, and they are both the same. No errors at all. Is there a way to get the data from fullCalendar, to see what it actually should display, as to determine if it is a data problema (probably related to scope) or just a display problem? – aplon May 02 '17 at 11:40
  • I used `$(".calendar").fullCalendar('getEventSources')`and it return an empty array when using the Factory variable. – aplon May 02 '17 at 11:45
  • It also returns an empty array when fetching the data from CRM – aplon May 02 '17 at 11:46
  • is the calendar object getting destroyed when you hide it (i.e. when you go to the view that lets you add an event)? I don't really know how Angular works in that respect, having never used it. Also...show your FullCalendar config? Are you definitely using event sources, rather than just a straight "events" definition? – ADyson May 02 '17 at 12:56
  • I think I have nailed down the problem and it is related to Angular. The ui-anguar directive gets fired before the promise returns the data. Will post the calendar config in the original post. I was not using eventSources, as the events did not get rendered (as the directive got fired before the eventSources object got filled out in the promise resolve). – aplon May 02 '17 at 13:00

1 Answers1

0

I'm posting the answer in case anyone else out there gets into the same issue. Thanks to @Javarome (https://stackoverflow.com/users/650104/javarome) in the post: Directive is being rendered before promise is resolved. I followed his suggestion and everything worked like a charm.

Summary: the issue was that the directive was getting fired before the promise resolved in the controller. So I followed his suggestion to wrap the directive in an ng-if (with the variable needed to be resolved as the trigger, and voila!!! Something like this:

<div class="container" ng-if="vm.fullCalendarEvents">
    <div class="calendar" ng-model="eventSources" calendar="calendar" config="uiConfig.calendar" ng-disabled="waitingForHttp" ui-calendar="vm.uiConfig.calendar" ></div>
</div>
Community
  • 1
  • 1
aplon
  • 445
  • 6
  • 24