ui-calendar
ui-calendar copied to clipboard
First event in an eventsource does not render
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 sourcesChanged
flag 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
Anybody wanna take a stab at this? @Sefriol @joshkurz Seems to be an issue that has been haunting for quite a long time
@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 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!
:+1:
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 If you need your events to stay in your calendar, they need to be set sticky as well. $scope.events[1].push({sticky: true})
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?
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
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?)
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
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?
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"]
});
}
Has anyone found a good workaround for this problem?
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.
+1
I met this issue too. Fixed by adding $timeout on eventsWatcher.
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.
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>