Используя последнюю версию fullCalendar (5.3.2), я хочу скрыть некоторые события, относящиеся к ресурсам, которые я не хочу показывать сейчас в данном представлении. Стандартный способ сделать это — использовать функцию eventClassNames
для проверки и добавления «скрытого» класса. Что-то вроде этого:
eventClassNames: function(arg) {
my_class = "";
if (arg.view.type != 'resourceTimeGridDay') {
if (arg.event.extendedProps.real_rc != "1") {
my_class = 'hidden';
}
}
return my_class;
}
используя простой CSS:
.fc-event.hidden {
display: none;
}
Это прекрасно работает, но возникает проблема, когда скрытое событие перекрывается с отображаемым. Например, в этом случае:
events: [
{
title: 'Resource 1',
real_rc: '1',
start: '2020-12-22 16:00',
end: '2020-12-22 17:00'
},
{
title: 'Resource 2',
real_rc: '2',
start: '2020-12-22 15:00',
end: '2020-12-22 17:00'
}
]
Должно отображаться только событие с real_rc == 1
, и на самом деле это правильно, но пространство, используемое скрытым событием, зарезервировано, как вы можете видеть на этом изображении:
Если событие с real_rc: 2
опущено в списке event
, результат будет ожидаемым:
Я использовал Chrome DevTools, чтобы попытаться выяснить, что происходит, и я думаю, что проблема в том, что «скрытый» класс установлен не на «самом внешнем элементе события», как fullCalendar указывает, а на внутренний:
(первый DIV — это первое событие, и, как вы можете видеть, класс hidden
установлен, но не для DIV, а для тега a
)
ИМХО это полный баг календаря, но сейчас у меня проблема и мне нужно решение. Мои варианты:
$(".fc-event.hidden").parent().remove()
, когда события загружаются и отображаются, но , поскольку v3 ничего подобного не существует UPDATE, и даже если он существует, с текущей версией v5 удаление элемента DOM не изменяет размер других полей событий.real_rc != 1
Есть ли способ обойти эту проблему, не создавая новую? (Я чувствую, что самый простой вариант - найти крючок, который позволит мне сделать вариант номер 2, но я потратил весь день и ничего не нашел).
@ADyson проблема с jQuery заключается в том, что, насколько мне известно, нет перехватчиков или обратных вызовов, куда я могу добавить код и гарантировать, что события загружаются и отображаются. В v3 был обратный вызов, но его убрали.
О каких именно крючках вы говорите? Некоторые вещи изменились между версиями, но, насколько я знаю, очень мало, если вообще что-то, было удалено. Например, все еще есть хуки рендеринга событий.
@ADyson Да, для рендеринга существуют отдельные события, но не глобальные. В v3 существовал eventAfterAllRender
( fullcalendar.io/docs/v3/eventAfterAllRender). С этим я могу получить надежную точку, где я могу очистить нежелательные события, но в версии 5 единственным местом является eventDidMount
, но это вызывается только один раз, поэтому, если движок снова отрендерит (т.е. щелкнет по изменению представления), события будут отображаться. снова и eventDidMount
не будет вызываться.
Это интересно. Мне нужно рассмотреть его поближе, но сейчас нет времени... может быть, через несколько дней, когда Рождество закончится. Прокомментируйте здесь, если вы сделаете какой-либо прогресс до этого, то я не трачу время впустую :-).
Конечно, @ADyson, и счастливого Рождества!
почему вы не используете правильное пользовательское представление для событий с правильными отступами и полями?
Спасибо @saqibkafeel, это еще один вариант. Я не использую пользовательские представления, потому что мне просто нужны классические представления, но они работают как положено. Я буду исследовать, может ли это решить проблему.
да, вы можете создать свой собственный вид как классический интерфейс просмотра
@saqibkafeel Я пытался, но безуспешно. Может быть, вы можете дать ответ с данным codepen.
@saqibkafeel Нет, результат должен быть как на втором изображении, которое я разместил: i.stack.imgur.com/blrRH.png Т.е. когда событие не отображается, ему не нужно резервировать место для себя
@Ivan Я уже исправил проблему с помощью eventDidmout, если вы видите в моем ответе, в противном случае предоставьте мне правильный код codePed с проблемой производительности загрузки событий, я также отлажу его, спасибо, и я думаю, что баллы за вознаграждение должны увеличиться
Как вы уже заметили, CSS и JS здесь не помогут, потому что события размещаются с помощью position:absolute
, поэтому удаление одного события (даже полное из DOM) не повлияет на отображение других. Единственный способ - удалить событие из календаря перед рендерингом.
Поэтому удалите событие вместо добавления класса:
eventClassNames: function(arg) { /* you can also use "eventDidMount" */
if (arg.view.type != 'resourceTimeGridDay') {
if (arg.event.extendedProps.real_rc != "1") {
arg.event.remove(); /* HERE */
}
}
},
Полный код:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
initialDate: '2020-12-22',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
height: 'auto',
eventClassNames: function(arg) {
if (arg.view.type != 'resourceTimeGridDay') {
if (arg.event.extendedProps.real_rc != "1") {
arg.event.remove();
}
}
},
events: [
{
title: 'Test Resource 1',
real_rc: '1',
start: '2020-12-22 13:00',
end: '2020-12-22 14:00'
},
{
title: 'Also resource 1',
real_rc: '1',
start: '2020-12-22 13:30',
end: '2020-12-22 14:30'
},
{
title: 'Resource 1',
real_rc: '1',
start: '2020-12-22 16:00',
end: '2020-12-22 17:00'
},
{
title: 'Resource 2',
real_rc: '2',
start: '2020-12-22 15:00',
end: '2020-12-22 17:00'
}
]
});
calendar.render();
});
html, body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 1100px;
margin: 40px auto;
}
<link rel = "stylesheet" href = "https://unpkg.com/[email protected]/main.min.css">
<script src = "https://unpkg.com/[email protected]/main.min.js"></script>
<div id='calendar'></div>
Другая идея состоит в том, чтобы контролировать display
события, как показано ниже:
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
initialDate: '2020-12-22',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
height: 'auto',
eventDidMount: function(arg) {
if (arg.view.type != 'resourceTimeGridDay') {
if (arg.event.extendedProps.real_rc != "1") {
arg.event.setProp( 'display', 'none' );
}
}
},
events: [
{
title: 'Test Resource 1',
real_rc: '1',
start: '2020-12-22 13:00',
end: '2020-12-22 14:00'
},
{
title: 'Also resource 1',
real_rc: '1',
start: '2020-12-22 13:30',
end: '2020-12-22 14:30'
},
{
title: 'Resource 1',
real_rc: '1',
start: '2020-12-22 16:00',
end: '2020-12-22 17:00'
},
{
title: 'Resource 2',
real_rc: '2',
start: '2020-12-22 15:00',
end: '2020-12-22 17:00'
}
]
});
calendar.render();
});
html, body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 1100px;
margin: 40px auto;
}
<link rel = "stylesheet" href = "https://unpkg.com/[email protected]/main.min.css">
<script src = "https://unpkg.com/[email protected]/main.min.js"></script>
<div id='calendar'></div>
Интерактивная демонстрация, в которой вы можете переключать отображение:
var rc = "1";
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
initialDate: '2020-12-22',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay'
},
height: 'auto',
eventDidMount: function(arg) {
if (arg.view.type != 'resourceTimeGridDay') {
if (arg.event.extendedProps.real_rc != rc) {
arg.event.setProp( 'display', 'none' );
}
}
},
viewDidMount: function(arg) {
var es = calendar.getEvents();
for(var i=0;i<es.length;i++)
es[i].setProp( 'display', 'auto' )
},
events: [
{
title: 'Test Resource 1',
real_rc: '1',
start: '2020-12-22 13:00',
end: '2020-12-22 14:00'
},
{
title: 'Also resource 1',
real_rc: '1',
start: '2020-12-22 13:30',
end: '2020-12-22 14:30'
},
{
title: 'Resource 1',
real_rc: '1',
start: '2020-12-22 16:00',
end: '2020-12-22 17:00'
},
{
title: 'Resource 2',
real_rc: '2',
start: '2020-12-22 15:00',
end: '2020-12-22 17:00'
}
]
});
calendar.render();
document.querySelector("#toggle").addEventListener('click',function() {
if (rc= = "1") rc = "2"; else rc = "1";
/* trigger view change */
calendar.changeView('dayGridMonth');
calendar.changeView('timeGridWeek');
});
});
html, body {
margin: 0;
padding: 0;
font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
font-size: 14px;
}
#calendar {
max-width: 1100px;
margin: 40px auto;
}
<link rel = "stylesheet" href = "https://unpkg.com/[email protected]/main.min.css">
<script src = "https://unpkg.com/[email protected]/main.min.js"></script>
<button id = "toggle">toggle</button>
<div id='calendar'></div>
Спасибо, но у этого подхода есть проблема, как я упоминал в пункте № 4: вы удаляете события, поэтому вам нужно перезагрузить их, если есть представление об изменении. Это проблематично по двум причинам: во-первых, потому что AFAIK v5 не имеет хука для changeView, а во-вторых (что более важно), потому что вам каждый раз нужен дополнительный вызов AJAX (и это занимает много времени, потому что я получаю тысячи событий).
Извините, я нашел хук для изменения представления: viewDidMount. С этим крючком ваше решение осуществимо. Мне нужно сделать вызов AJAX, но, по крайней мере, это сработает.
@Ivan первый фрагмент удаляется, а второй только прячется. С отображением событие все еще существует, и вы все равно можете обновить его позже, я думаю (попробую обновить на примере)
Да, второй только скрывает, но eventDidMount
вызывается только один раз при загрузке событий, поэтому, если resourceTimeGridDay
- это вид при загрузке событий, то они не скрыты, а если нет, то они скрыты всегда. Ожидаемое поведение похоже на то, когда вы используете eventClassNames
, который вызывается с каждым рендерингом события, поэтому с каждым изменением представления событие получает тот или иной класс.
@Ivan Я добавил еще один пример с переключением отображения при нажатии
Спасибо! Этот подход путем перечисления событий и изменения их свойств является новым для меня, и он хорошо работает в качестве обходного пути, пока эта ошибка полного календаря не будет исправлена.
Вы можете решить эту проблему, используя селектор CSS.
Я решил это в ответ, используя функцию рендеринга, которая возвращает компонент события с именем класса, например «my-event hidden», и добавил стиль, подобный следующему:
a.fc-event:has(.my-event.hidden) {
position: absolute !important;
top: -9999px !important;
left: -9999px !important;
}
Ничто не мешает вам использовать jQuery, если вы этого хотите. jQuery по-прежнему можно использовать для управления элементами HTML в календаре. Тот факт, что fullCalendar перестал использовать его для внутренних целей, не мешает вам добавить его на свою страницу.