Grid View Customization

  • **Issue description:
  • I am looking for a way to customize the grid view to show only one month at a time but also have the ability to swap months, similar to the calendar view. I have an idea of how to accomplish this but am having some issues creating the JS myself. Here is how I think it can be accomplished if someone can help determine the correct coding:
  1. Set grid view to “group by month” and set number of months to display to “12”.
  2. In CSS, (or a JS equivalent), set Grid Groups to the following:
    .eapp-events-calendar-grid-group:nth-of-type(n+2) {
    display: none !important;
    }
  3. Where I am running into issues - Create a button element with text “Next Month” to append to .eapp-events-calendar-date-element-item that, on click, will hide current (December for example) .eapp-events-calendar-grid-group and display the subsequent (January) .eapp-events-calendar-grid-group.
  4. If possible, it would also be great to have a second button with text “Previous Month” to prepend to .eapp-events-calendar-date-element-item that would do the reverse function (hide current and display previous).

Any help would be greatly appreciated as this would drastically improve the user experience of the Events Calendar module for my organization!


2 Likes

Hi there and welcome to the Community, @DustinVance :wave:

Right now, it’s impossible to customize the widget this way, but we have a Wishlist request for the Carousel layout, that should be the right option for this - Carousel Layout

Feel free to upvote this idea to not miss any updates :slightly_smiling_face:

1 Like

Hey Max, thanks for the follow-up! I was actually able to accomplish what I was trying to do with a little experimentation and some JS from the custom filters post, thought it isn’t completely perfect yet.

I do have a follow-up question though, if you are able to help. Is there some javascript code to reset all of the filter for grid view?

2 Likes

Hi there, @DustinVance :wave:

Wow, that’s amazing! Happy to hear that you’ve managed to achieve this :wink:

Could you please send me a link to the page where your widget is installed? I’ll be happy to check things for you!

1 Like

Hey Max,

Thanks for the follow-up. Here is a link to the embedded calendar: Test Page — CAP

As you will see, I have the “Previous Month” & “Next Month” buttons working. However, if there is a filter combination that yields no events, the error message displays, and even after clearing the filters, no events populate.

I managed to create a new button called “Reset Filters”, and this button will reset the month back to the current month and show it. But if possible, I would love this button to also reset any current filters to default so someone doesn’t have to manually remove them. Hope that makes sense, and happy to provide more info if needed.

2 Likes

@DustinVance, A huge thank you for such a thorough response, that’s much appreciated!

I’ve passed your request on to the dev team and will let you know once they respond :wink:

2 Likes

Hi there, @DustinVance :wave:

Here is the adjusted code:

const resetButton = document.createElement('div');
resetButton.textContent = '⎋ Reset Filters';
resetButton.classList.add('reset-button');
resetButton.addEventListener('click', function () {
	$('.eapp-events-calendar-grid-group').removeClass('current');
	setTimeout(() => {
		monthGrid[0].classList.add('current');
		monthGrid[0].classList.add('first');
	}, 100);

	const filters = widget.querySelectorAll(
		'.eapp-events-calendar-filter-current'
	);

	filters.forEach((filter) => {
		if (filter.classList.contains('eapp-events-calendar-filter-filtered')) {
			filter.click();
			const dropdownItems = document.querySelectorAll(
				'.eapp-events-calendar-filter-item'
			);
			dropdownItems.forEach((dropdownItem) => {
				if (dropdownItem.textContent === 'All') {
					dropdownItem.click();
				}
			});
		}
	});
});

Please check your website and let me know how the code works :slightly_smiling_face:

1 Like

That worked beautifully! Thank you so much Max and team for the support here in getting this customized.

3 Likes

Awesome, you’re always welcome :wink:

1 Like

Just putting the solution here to help anyone that would like it until we get a similar feature natively! Full disclaimer, I am not super proficient Javascript coder, so if anyone has a way to improve this code and its overall functionality, please feel free to!

Important Issues to Note when Implementing

  • The JS only runs outside of the editor, so when in the editor, all events will be hidden due to the CSS. I haven’t figured out how to only have the CSS run on the calendar embed, so I manually “turn off” the display:none CSS when editing to view the calendar items in the editor, and then “turn it back on” when publishing to make the code work when live.

  • This code doesn’t play nicely with the date filter, so I have the date filter hidden using CSS.

  • As mentioned above, if there is a combo of filters that produces no result, it will cause the code to break temporarily. To remedy this, I created a “Reset Filters” button that will reset the calendar back to the current month and turn off all filters.

Layout Settings

Layout: Grid View
Group Events By: Month
Months to Display: 120 (this can be any number. I just used a large number to get it to show far into the future.)

Custom Code for a Click-Through Single Month View in Grid View:

Javascript

const waitForElement = (selector, root = document) =>
  new Promise((res) => {
    let i = 0;

    const check = () => {
      const component = root.querySelector(selector);

      if (component) {
        res(component);
      } else if (i !== 50) {
        setTimeout(check, 100);
        i++;
      }
    };

    check();
  });

waitForElement('.eapp-events-calendar-events-calendar-component').then(
  (widget) => {
    
    const monthGrid = document.getElementsByClassName('eapp-events-calendar-grid-group');
    monthGrid[0].classList.add('current');
    monthGrid[0].classList.add('first');
    
    const previousButton = document.createElement('div');
    previousButton.textContent = '◂ Previous Month';
    previousButton.classList.add('previous-month');
    previousButton.addEventListener('click', function() {
      $('.eapp-events-calendar-grid-group.current:not(:first-child)')
      .removeClass('current')
      .prev()
      .addClass('current');
});

const nextButton = document.createElement('div');
    nextButton.textContent = 'Next Month ▸';
    nextButton.classList.add('next-month');
    nextButton.addEventListener('click', function() {
      $('.eapp-events-calendar-grid-group.current:not(:last-child)')
      .removeClass('current')
      .next()
      .addClass('current');
});

const resetButton = document.createElement('div');
resetButton.textContent = '⎋ Reset Filters';
resetButton.classList.add('reset-button');
resetButton.addEventListener('click', function () {
	$('.eapp-events-calendar-grid-group').removeClass('current');
	setTimeout(() => {
		monthGrid[0].classList.add('current');
		monthGrid[0].classList.add('first');
	}, 100);

	const filters = widget.querySelectorAll(
		'.eapp-events-calendar-filter-current'
	);

	filters.forEach((filter) => {
		if (filter.classList.contains('eapp-events-calendar-filter-filtered')) {
			filter.click();
			const dropdownItems = document.querySelectorAll(
				'.eapp-events-calendar-filter-item'
			);
			dropdownItems.forEach((dropdownItem) => {
				if (dropdownItem.textContent === 'All') {
					dropdownItem.click();
				}
			});
		}
	});
});



// Place the buttons in filter container
    let filterContainer = widget.querySelector(
      '.eapp-events-calendar-controls-component'
    );
    if (!filterContainer) {
      let header = widget.querySelector(
        '.eapp-events-calendar-events-calendar-header'
      );
      if (!header) {
        header = document.createElement('div');
        header.classList.add('eapp-events-calendar-events-calendar-header');
        widget.prepend(header);
      }

      filterContainer = document.createElement('div');
      filterContainer.classList.add('eapp-events-calendar-controls-component');
      header.append(filterContainer);
    }
    filterContainer.insertBefore(previousButton, filterContainer.childNodes[0]);
    filterContainer.insertBefore(nextButton, filterContainer.childNodes[1]);
    filterContainer.appendChild(resetButton);
  });

CSS

.eapp-events-calendar-dates-input {
  display: none;
}

.eapp-events-calendar-grid-group {
  display: none;
}

.eapp-events-calendar-grid-group.current {
  display: block;
}

.previous-month, .next-month, .reset-button {
align-items: center;
border-radius: 4px !important;
border: solid 1px rgba(29, 40, 88, 0.12) !important;
box-sizing border-box !important;
color: rgb(29, 40, 88);
cursor: pointer !important;
display: flex;
font-size: 13px !important;
text-transform: uppercase !important;
height: auto;
letter-spacing: 0.16px;
line-height: 20.8px;
margin: 3px;
max-width: 200px;
outline-style: none;
outline-width: 0px;
overflow-wrap: break-word;
overflow-x: hidden;
overflow-y: hidden;
padding-bottom: 10px;
padding-left: 12px;
padding-right: 12px;
padding-top: 10px;
text-overflow: ellipsis;
text-size-adjust: 100%;
text-transform: none;
text-wrap-mode: nowrap;
transition-behavior: normal;
transition-delay: 0s;
transition-duration: 0.2s;
transition-property: all;
transition-timing-function: ease;
unicode-bidi: isolate;
white-space-collapse: collapse;
width: auto;
-webkit-font-smoothing: antialiased;
}

.previous-month:hover, .next-month:hover, .reset-button:hover {
  border: solid 1px rgb(29, 40, 88) !important;
}
3 Likes

Fantastic, @DustinVance! Thanks a million for your input - that’s much appreciated :heart: