3

In dayGridMonth I want to see a subset of the events, and in listMonth I want to see all of them.
E.g. in the grid view I don't want to see events with title break (in my actual case it is a more complex rule: only show unique event titles).

I tried:

eventDidMount: function(info) {
  if (info.view.type == 'dayGridMonth' && info.event.title == 'break') {
    info.event.setProp('display','none')
  }
}

This does hide them, but when switching from dayGridMonth to listMonth the hidden events don't come back. I don't mind storing + restoring the original display value, but the events don't appear at all any more in eventDidMount after switching views.

How do I "set the property display:none" only for that view?

wivku
  • 2,457
  • 2
  • 33
  • 42

2 Answers2

1

Thanks to @ADyson for the useful suggestion: hide using CSS.
Even better, with the use of eventClassNames it is super straightforward, the classes "reset" for each render.

What I ended up with:

...
.fc-event.hidden {
  display: none;
}

let calendar = new Calendar(calendarEl, {
...
  eventClassNames: function(info) {
    var classes = []
    if (info.view.type == 'dayGridMonth' && info.event.title == 'break') {
      classes.push('hidden')
    } 
    // other rules for classes
    return classes
  }
...
}

One issue: after the hidden events, the next one has a margin-top: 18px resulting in a gap:

<div class="fc-daygrid-event-harness fc-daygrid-event-harness-abs" style="visibility: hidden;">
  <a class="fc-daygrid-event fc-daygrid-dot-event fc-event fc-event-start fc-event-end fc-event-past city hidden" href="xyz" style="color: black;">
    <div class="fc-daygrid-event-dot" style="..."></div>
    <div class="fc-event-title">break</div>
  </a>
</div>

<div class="fc-daygrid-event-harness" style="margin-top: 18px;">
  <a class="fc-daygrid-event fc-daygrid-dot-event fc-event fc-event-start fc-event-end fc-event-past" href="http://xyz" style="color: black;">
    <div class="fc-daygrid-event-dot" style="..."></div>
    <div class="fc-event-title">1st event after hidden events</div>
  </a>
</div>

enter image description here

wivku
  • 2,457
  • 2
  • 33
  • 42
  • The gap is because event elements are positioned on the grid using "sticky" positioning (a form of fixed positioning). Not much you can do about that unless you want to re-write fullCalendar's rendering algorithms, I suspect. If it's a big problem for you, you'd have to go back to the idea of filtering at the event feed level. – ADyson Jul 08 '20 at 22:50
0

Try adding an else to reset the event's display property on other views:

eventDidMount: function(info) {
  if (info.view.type == 'dayGridMonth' && info.event.title == 'break') {
    info.event.setProp('display','none')
  }
  else info.event.setProp('display', 'auto');
}
ADyson
  • 57,178
  • 14
  • 51
  • 63
  • That will not work. First time the calendar is rendered e.g. 10 items trigger `eventDidMount()` during which e.g. 4 are set to `display:none`, the second time the calendar is rendered `eventDidMount()` is only triggered for the remaining 6. – wivku Jul 08 '20 at 11:22
  • ah ok, I think I see what must be happening then - because it was set to display none, it does not render again, so this callback never occurs. – ADyson Jul 08 '20 at 11:32
  • I wonder if you'd be better separating the "break" events into a different event source, and then switching that event source on and off when the view type changes. Or, I haven't tried, but I wonder if you can specify different event sources for each view, using [view-specific options](https://fullcalendar.io/docs/view-specific-options). – ADyson Jul 08 '20 at 11:36
  • I have a single JSON event source. The simplified example it is based on "break" in title, but in the actual case I look for unique titles. E.g. if there are 3 "supermarket" events, then I only show the first one. Another generic use case would be: programmatically + dynamically hide certain events (e.g. click button to hide "low priority" events). Not possible to specify different event sources for each view. – wivku Jul 08 '20 at 11:59
  • In that case I suspect maybe your only other option is to do filtering of the event data itself (e.g. using eventDataTransform to set the display property based on the current view) and make sure fullCalendar refetches the events from the source every time the view changes (you can do this by setting lazyFetching to false - but make sure you understand the implications, see https://fullcalendar.io/docs/lazyFetching) or whenever you press your filtering button. N.B. If your events are relatively static you could potentially use some caching to alleviate load on the server. – ADyson Jul 08 '20 at 12:12
  • Oh sorry, one other idea, going back to the eventDidMount option: instead of setting the "display" property of the event object, you could try setting the CSS display property of the DOM element instead. e.g. `info.el.style.display = "none";` and `info.el.style.display = "block";` (respectively in the if and the else). I suspect fullCalendar may not notice this in the same way it notices the event's "display" property, and would therefore still run the rendering routine. I can't test it right now but I think it's worth a try, probably simpler than arranging to filter the source. – ADyson Jul 08 '20 at 12:15
  • CSS: that's a good one (duh!), will try that and let you know. – wivku Jul 08 '20 at 12:32