Data vanishing upon selection of a date or update of the month

I have implemented VanillaCalendar to display events on specific days.

You can view the complete demo in the code snippet provided below or by visiting it on CodePen

The functionality involves iterating through JSON data and adding a div element to days with events. Here's how it works:

const assignEventsToCalendar = function() {
  let eventData = data;
  for (const {month, days} of eventData) {
    for (const {day, events} of days) {
      const key = day.split('-').map(p => p.padStart(2, '0')).join('-');
      let dayElement = document.querySelector(`[data-calendar-day="${key}"]`);
 
      if (dayElement) { // only apply flair if day exists (is in current month)
        let eventWrapper = document.createElement("div");
        eventWrapper.classList.add("event-wrapper");
        dayElement.append(eventWrapper);

        for (const {title, category} of events) {
          let singleEvent = document.createElement("div");
          singleEvent.classList.add("event", category);
          eventWrapper.append(singleEvent);
        }
      }
    }
  }
};

The issue arises when clicking on a day or changing the month using the navigation arrows, causing the event markers on the days to disappear. This makes it difficult to track which events are scheduled on each day.

One approach is to utilize the VanillaCalendar event to trigger the function when navigating between months; however, this method may not cover all user interactions.

actions: {
  clickArrow(e, self) {
    setTimeout(assignEventsToCalendar, 1000);
  }
}

Is there a way to address this challenge using JavaScript?

Code Snippet

let data = [{"month":"2024-2","days":[{"day":"2024-2-15","events":[{"title":"Event One","category":["Category1"]}]},{"day":"2024-2-21","events":[{"title":"Event Two","category":["Category2"]},{"title":"Event Three","category":["Category1"]}]},{"day":"2024-2-20","events":[{"title":"Event Four","category":["Catgory2"]}]}]},{"month":"2024-3","days":[{"day":"2024-3-2","events":[{"title":"Event Five","category":["Category1"]}]},{"day":"2024-3-23","events":[{"title":"Event Six","category":["Category2"]}]}]}];

document.addEventListener("DOMContentLoaded", function() {
  var currentDate = new Date().toISOString().slice(0, 10);

  var options = {
    date: {
      min: "1920-01-01",
      max: "2038-12-31"
    },
    settings: {
      range: {
        min: currentDate
      },
      visibility: {
        disabled: true,
        theme: 'light'
      }
    },
    actions: {
      clickArrow(e, self) {
        setTimeout(assignEventsToCalendar, 1000);
      }
    }
  };

  var calendar = new VanillaCalendar("#calendar", options);
  calendar.init();

  assignEventsToCalendar();
});

const assignEventsToCalendar = function() {
  let eventData = data;
  for (const {
      month,
      days
    } of eventData) {
    for (const {
        day,
        events
      } of days) {
      const key = day.split('-').map(p => p.padStart(2, '0')).join('-');
      let dayElement = document.querySelector(`[data-calendar-day="${key}"]`);

      if (dayElement) { // only apply flair if day exists (is in current month)
        let eventWrapper = document.createElement("div");
        eventWrapper.classList.add("event-wrapper");
        dayElement.append(eventWrapper);

        for (const {
            title,
            category
          } of events) {
          let singleEvent = document.createElement("div");
          singleEvent.classList.add("event", category);
          eventWrapper.append(singleEvent);
        }
      }
    }
  }
};
#calendar {
  max-width: 350px;
}

.vanilla-calendar-day__btn {
  .event-wrapper {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: auto;
  }
  .event {
    display: inline-block;
    margin-right: 2px;
    width: 5px;
    height: 5px;
    &.Category1 {
      background-color: red;
    }
    &.Category2 {
      background-color: blue;
    }
  }
}
<div id="calendar"></div>

<script src="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/vanilla-calendar.min.js"></script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/vanilla-calendar.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/themes/light.min.css">

Answer №1

To highlight specific dates and add custom pop-ups using CSS classes, you can utilize the Pop-ups feature.

If you prefer using boxes or divs to mark the days, one approach is to employ ::after for creating pseudo-elements with customized content or styling:

document.addEventListener("DOMContentLoaded", function() {
  var currentDate = new Date().toISOString().slice(0, 10);

  var options = {
    date: {
      min: "1920-01-01",
      max: "2038-12-31"
    },
    settings: {
      range: {
        min: currentDate
      },
      visibility: {
        disabled: true,
        theme: 'light'
      }
    },
    popups: {
      '2024-02-15': {
        modifier: 'event',
        html: 'Event One<br/>Event Two',
      },
      '2024-02-27': {
        modifier: 'event',
        html: 'Event One<br/>Event Two',
      }
    }
  };

  var calendar = new VanillaCalendar("#calendar", options);
  calendar.init();

});
#calendar {
  max-width: 350px;
}

.event:after {
  content: "📦";
  display: block;
  height: 5px;
  width: 5px;
  position: absolute;
  bottom: 5px;
  left: 0;
}
<div id="calendar"></div>

<!-- Include Vanilla Calendar scripts -->
<script src="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/vanilla-calendar.min.js"></script>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/vanilla-calendar.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@uvarov.frontend/vanilla-calendar/build/themes/light.min.css">

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to provide unrestricted support for an infinite number of parameters in the typing of the extend function from Lodash

I am utilizing the "extend" function from lodash to combine the objects in the arguments as follows: import { extend } from 'lodash'; const foo1 = { item: 1 }; const foo2 = { item: 1 }; const foo3 = { item: 1 }; const foo4 = { item: 1 }; const f ...

Working together: combining ngMessages with a datepicker

In my Angular project, I am utilizing ngMessages for form validation and am encountering an issue when using it with a Datepicker. After selecting a date, the ng-message does not disappear, indicating that ngMessages is not detecting any events being tri ...

How can we determine if the user is on a small device and utilizing flexbox with col-sm?

Is there a method to detect when the user is on a small device? I'm looking to adjust my navigation menu based on the size of the device, similar to the col-sm functionality. ...

KineticJS: Applying a filter to an image does not result in the image having a stroke

Working with KineticJS version 5.1.0 I encountered an issue where a KineticJS image that had a stroke lost the stroke after applying a filter to it. I have created a demo showcasing this problem, which can be viewed on JSFiddle. Here is the code snippet: ...

Update overall font size to be 62% for a consistent look across the website

Recently, I developed a browser extension that adds an overlay button to the LinkedIn website. Everything was running smoothly until I discovered that LinkedIn uses a global font-size: 62,5% that completely messes up my design.. https://i.stack.imgur.com ...

The fuse-sidebar elements are not being properly highlighted by Introjs

I have recently developed an angular project that utilizes the fuse-sidebar component. Additionally, I am incorporating introjs into the project. While introjs is functioning properly, it does not highlight elements contained within the fuse-sidebar. The ...

Issue encountered while attempting to attach an event listener to an element within a class

Upon running the code, I encountered an error message that reads: Uncaught TypeError: this.startButton.addEventListener is not a function and I'm unsure of how to resolve it. Although I can successfully console.log the button inside the class, adding ...

Using node.js http.request to retrieve JSON data when the JSON data is not defined beforehand

Struggling to retrieve data from embed.ly using node.js. Seems like everything is set up correctly, but there's an "undefined" prefixing the data: Wondering if it's related to setEncoding('utf8) ? Here's what the output looks like: ...

Using Typescript to implement a conditional return type and ensuring that the value types are consistent together

I am working with a useSelectedToggle hook that helps in connecting the UI state to the open/closed status of a dialog where it will be displayed. The toggle defines the value as (T) when it is open, and null when it is closed. How can I enforce stricter ...

Avoid the issue of markers clustering in Leaflet to have distinct markerClusterGroup icons without overlap

Is there a way to prevent two separate markerClusterGroups from overlapping in Leaflet? I have one with a custom Icon to differentiate between the two clusters, but for simplicity's sake, I've omitted that part in this example. var map = L.map(&q ...

What is the best way to delete rows from an HTML table?

I am trying to update the table, but every time the setInterval function is triggered, the append method adds the same rows again. I want the old rows to be removed before inserting the new ones. $(document).ready(function() { function updateT ...

(perhaps) just a question regarding AJAX and PHP

Having a bit of trouble here - I have two files, main.html and processing.php. In the php file, I am trying to update a specific element on main.html, but I can't seem to retrieve either the html or javascript value from main.html For instance, main. ...

Retrieve the selected date from the date picker widget

Welcome to my custom datepicker! Here is the HTML code: <div class="field-birthday field-return" id="birthday-edit" style="display:none;"> <div class="birthdaypicker"></div> <input class="hidden" name="birthday" type="hidden" ...

Utilize HTML5 localStorage functionality

I have a good understanding of utilizing HTML5 localStorage with methods like localStorage.getItem/setItem. However, I am currently trying to figure out the implementation for a dynamic page. Let me explain the scenario: On my dynamic page (myPage.jsp), ...

The CSS formatting is not being properly applied within the innerHTML

I have a scenario where I am trying to display a Bootstrap card using innerHTML in my TS file, but the styles are not being applied to this content. I suspect that the issue might be because the styles are loaded before the component displays the card, cau ...

What purpose do controller.$viewValue and controller.$modelValue serve in the Angular framework?

I'm confused about the connection between scope.ngModel and controller.$viewValue/controller.$modelValue/controller.$setViewValue(). I'm specifically unsure of the purpose of the latter three. Take a look at this jsfiddle: <input type="text" ...

vue.js experiences a delay in firing the mouseleave event

My sidebar is a simple design in HTML with a script that causes it to open and close when the mouse enters and leaves. I utilized Vue.js for the entire sidebar, everything is functioning well except for one issue - when the mouse hovers over an item in the ...

Can AJAX be considered a backend tool for retrieving data from servers?

I'm curious to find out if ajax is primarily used as a backend technology for retrieving data or if it's mainly considered a frontend tool. My attempts to research this on Google have not yielded a definitive answer. ...

Preventing the submission of a form using jQuery until all input, radio, select, and checkbox fields are filled out

I currently have a form that includes various field types, all of which must be filled out before submission. The submit button is disabled by default and I am looking to enable it once all fields are completed. I came across examples of this feature work ...

When you select a checkbox, it successfully toggles the first time, but fails to do so the second time [S

When it comes to issuing invoices, here's the process I follow: First, I make sure to select all invoices on the current page by clicking on the checkbox. Then I proceed to hit the issue button and give my approval for them to be issued. Once the cu ...