ui-calendar icon indicating copy to clipboard operation
ui-calendar copied to clipboard

First event in an eventsource does not render

Open laander opened this issue 9 years ago • 18 comments

For new event sources without any events (eventsource.events.length === 0), the first event pushed to it (eventsource.events.push({ // event })) does not render in the calendar. The issue is a follow-up on https://github.com/angular-ui/ui-calendar/issues/101

The problem, AFAIK, is that the sourcesChanged flag in the uiCalendar directive decides whether applyChanges(newTokens, oldTokens) (L161) should be called. This is fine, but I think that the flag is set too late in eventSourcesWatcher.onAdded (L265) and therefore is only checked in eventsWatcher.subscribe (L297) on the next digest/change, e.g. when a new event is added to said event source. This results in that event being "skipped" and therefore not rendered.

Solution 1) Remove the sourcesChanged check and settle on a few bit more unnecessary computing when its not needed.

Solution 2) Move the sourcesChangedflag a bit up the chain, so its set before being checked (honestly not sure how)

Solution 3) Have the eventSourcesWatcher.onAdded fired when the directive is initialized and not wait until an event occurs (like now).

EDIT: added line number refs

laander avatar Jun 11 '15 04:06 laander

Anybody wanna take a stab at this? @Sefriol @joshkurz Seems to be an issue that has been haunting for quite a long time

laander avatar Jun 11 '15 05:06 laander

@laander I agree with your analysis of the problem. I cam to the same conclusion. Regarding your solutions:

Solution 1) I think it will not work. AFAIK, if we remove the sourceChanged check, we might render the event twice. @joshkurz can you confirm?

Solution 2) I got the idea, but I don't know either how to achieve it

Solution 3) Doing something at init seems the most promising solution to me since the issue only shows up at init of the directive.

@laander @joshkurz I would like this issue to be solved and I am ready to help. As a first step, it would be great to write 2 tests:

  • 1 that fails with an empty eventSource
  • 1 that passes with an eventSource containing 1 event WDYT?

antoinepairet avatar Jun 11 '15 12:06 antoinepairet

@antoinepairet Good thoughts and I agree on your next step - I'm unfortunately not confident enough with the ui-calendar tests to do it myself.

I'm gonna hack around the code though, see if I can get solution 3) to work out. We use ui-calendar extensively at Timebird.io and I'd love to see this module improve. Help will be much appreciated!

laander avatar Jun 16 '15 20:06 laander

:+1:

angelxmoreno avatar Jun 23 '15 08:06 angelxmoreno

Hello,

I have too this problem. After loading page, i make searching using $http. However the data are updated and the screen of the calendar not updated. Below part the my code:


$planejamentocalendario.buscar($scope.filtro).then(function(req){
    var events = []
    angular.forEach(req.item, function(itemAgenda, index) {
        var dataAgendamento = new Date(itemAgenda.data);
        angular.forEach(itemAgenda.cliente, function(itemAgendaCliente, index) {
            $scope.events[1].push({
                title : itemAgendaCliente.nome,
                start : dataAgendamento,
                inicio : dataAgendamento,
                codigo : itemAgendaCliente.cod,
                className: ["openSesame"]
            });
        });
    });
    console.log($scope.events[1])
});

emirdeliz avatar Jun 25 '15 17:06 emirdeliz

@emirdeliz If you need your events to stay in your calendar, they need to be set sticky as well. $scope.events[1].push({sticky: true})

Sefriol avatar Jun 25 '15 21:06 Sefriol

Hello @Sefriol,

Thanks for help. Edited the code bellow the problem persisted. I discovered why this ocurred. When calling in promise angular this problem is represented. For some reason the calendar not is updated after the promise response.


$scope.evento = [];
$scope.eventoCalendario = [[], $scope.evento, []];
$scope.loading = function(regerar) {
    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();
          
    var staticEvents = 
        [{title: 'Static 1', start: new Date(y, m, 1), allDay: true},
        {title: 'Static 2', start: new Date(y, m, 8), allDay: true},
        {title: 'Static 3', start: new Date(y, m, d), allDay: true}];
    
    $planejamentocalendario.buscar("").then(function(req){
        $scope.renderizarEvento(staticEvents);
    });
};
    
$scope.renderizarEvento = function (item){
    var evento = [];
    $scope.evento.splice(0);
    
    angular.forEach(item, function(itemAgenda, index) {
        var dataAgendamento = itemAgenda.start;
        
        evento.push({
            title : itemAgenda.title, 
            start : dataAgendamento,
            allDay : true,
            sticky: true
        });
    });
    
    angular.forEach(evento, function (ev) {
        $scope.evento.push(ev);
    });
    
    uiCalendarConfig.calendars.calendario.fullCalendar( 'rerenderEvents' );
    console.log($scope.evento)
}

If calling renderizarEvento without promise works fine.


$scope.evento = [];
$scope.eventoCalendario = [[], $scope.evento, []];
$scope.loading = function(regerar) {
    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();
          
    var staticEvents = 
        [{title: 'Static 1', start: new Date(y, m, 1), allDay: true},
        {title: 'Static 2', start: new Date(y, m, 8), allDay: true},
        {title: 'Static 3', start: new Date(y, m, d), allDay: true}];
    
    $scope.renderizarEvento(staticEvents);
};
    
$scope.renderizarEvento = function (item){
    var evento = [];
    $scope.evento.splice(0);
    
    angular.forEach(item, function(itemAgenda, index) {
        var dataAgendamento = itemAgenda.start;
        
        evento.push({
            title : itemAgenda.title, 
            start : dataAgendamento,
            allDay : true,
            sticky: true
        });
    });
    angular.forEach(evento, function (ev) {
        $scope.evento.push(ev);
    });
    uiCalendarConfig.calendars.calendario.fullCalendar( 'rerenderEvents' );
    console.log($scope.evento)
}

Any idea?

emirdeliz avatar Jun 26 '15 00:06 emirdeliz

Some event of ui-calendar not running after loading promise. When clicked in buttons next and before this event is fired. Try click forced buttons after promise returned. But too not working

emirdeliz avatar Jun 26 '15 00:06 emirdeliz

Does the $scope.evento change in both cases? If it does, try to find if the EventSource from the calendar itself change. (Btw, is there any particular reason for 2x forEach loops? Couldn't you just push an event into the scope when you create it?)

Sefriol avatar Jun 26 '15 07:06 Sefriol

Try with one foreach and not work fine too. The question is, why when clicked in before and next works?

How to look the EventSource of calendar?

I Tried debug source of the calendar, but i not found the problem

emirdeliz avatar Jun 26 '15 12:06 emirdeliz

I guess this is when we add a new eventSource to the eventSources array that has length zero and then push to it? I just tried that and it works. Maybe im missing something. Can someone create a reproduction of this?

joshkurz avatar Aug 18 '15 21:08 joshkurz

Hello,

I tried various alternatives for this problem, but not got exit. I used other form especific for rule of business. This is my solution

<div id="calendario" ui-calendar="uiConfig.calendario" ng-model="evento" calendar="calendario"></div>

$scope.uiConfig = {
    calendario: {
        allDaySlot: false,
        editable: false,
        height: 400,
        timeFormat: "",
        header: {
            left: "",
            center: "title",
            right: "today prev,next"
        },
        buttonText:{
            today: "Hoje"
        }
    }
};

$scope.atualizarAgenda = function() {
    /*Limpa a lista para atualizar*/
    $scope.evento[1].splice(0, $scope.evento[1].length);
    /* Atualizar model do calendario inteiro */
    var formNeoId = 1;
    $planejamentocalendariovisita.buscar(formNeoId).then(function (req){
        angular.forEach(req, function (visita, index){
            $scope.adicionarVisita(visita);
        });
    });
};

$scope.adicionarVisita = function(visita) {
    $scope.evento[1].push({
        title: visita.venda.cliente.nome + "\n Esforço: " + $filter("currency")(visita.venda.esforcoVendaReais, "R$ ", "2"),
        start: new Date(visita.data),
        inicio: new Date(visita.data),
        codigo: visita.id,
        codigoCliente: visita.venda.cliente.id,
        status: visita.status,
        className: ["openSesame"]
    });
}

emirdeliz avatar Aug 18 '15 21:08 emirdeliz

Has anyone found a good workaround for this problem?

vlamic avatar Jan 07 '16 14:01 vlamic

Hello,

events on calendar are fetched by clicking previous and next button but they are not getting fetched at the time page reload and page refresh.

satinder15 avatar Apr 08 '16 06:04 satinder15

+1

schaib avatar Jun 24 '16 01:06 schaib

I met this issue too. Fixed by adding $timeout on eventsWatcher.

flniu avatar Apr 26 '17 14:04 flniu

It sounds silly, but as workaround I'm feeding the ui-calendar a dummy event (date: 01/01/1900) during onInit(), so that all the events I'm loading or creating subsequently are displayed correctly.

Mobiletainment avatar Feb 07 '18 17:02 Mobiletainment

Hello,

I came across with the same problem and I found a workaround for this issue:

In the controller function set showCalendar variable on scope and put a watcher like this:

$scope.showCalendar = false; $scope.$watch('events', function(newVal, oldVal) { if (newVal !== oldVal) { $scope.showCalendar = true; } }, true);

in the promise:

someService.getSomeData().then((res) => {
                $scope.events = res.data.map((someData) => {
                    return {
                        id: someData.id,
                        title: someData.title,
                        start: new Date(someData.dateAndTime),
                        allDay: false
                    }
                });
                $scope.eventSources = [$scope.events];
            }).catch((err) => {
                errorCallback(err);
            });

and in html code put this:

<div ui-calendar="uiConfig.calendar" ng-model="eventSources" ng-if="showCalendar" ></div>

RicardoCamilo avatar Sep 04 '18 18:09 RicardoCamilo