3

I have been working with some of the code samples for AlpineJS. At first the code would only do the year 2020, and would not move past December 2020.

I have managed to get the code to go past 2020 now, however the dates do not update in the calendar view and I cant see what I am missing.

I have my code on a JSFiddle, can anyone see where I am going wrong, as you can go past December 2020, and select a date which then populates the input field fine.

HTML

<div class="flex items-center justify-center">

<div class="antialiased sans-serif">
<div x-data="app()" x-init="[initDate(), getNoOfDays()]" x-cloak>
  <div class="container mx-auto px-4 py-2 md:py-10">
    <div class="mb-5 w-64">

      <label for="datepicker" class="font-bold mb-1 text-gray-700 block">Select Date</label>
      <div class="relative">
        <input type="hidden" name="date" x-ref="date">
        <input type="text" readonly x-model="datepickerValue" @click="showDatepicker = !showDatepicker" @keydown.escape="showDatepicker = false" class="w-full pl-4 pr-10 py-3 leading-none rounded-lg shadow-sm focus:outline-none focus:shadow-outline text-gray-600 font-medium" placeholder="Select date">

        <div class="absolute top-0 right-0 px-3 py-2">
          <svg class="h-6 w-6 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
          </svg>
        </div>

        <!-- <div x-text="no_of_days.length"></div>
                      <div x-text="32 - new Date(year, month, 32).getDate()"></div>
                      <div x-text="new Date(year, month).getDay()"></div> -->

        <div class="bg-white mt-12 rounded-lg shadow p-4 absolute top-0 left-0" style="width: 17rem" x-show.transition="showDatepicker" @click.away="showDatepicker = false">

          <div class="flex justify-between items-center mb-2">
            <div>
              <span x-text="MONTH_NAMES[month]" class="text-lg font-bold text-gray-800"></span>
              <span x-text="year" class="ml-1 text-lg text-gray-600 font-normal"></span>
            </div>
            <div>
              <button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full" @click="month--; getNoOfDays()">
                <svg class="h-6 w-6 text-gray-500 inline-flex" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
                </svg>
              </button>
              <button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full" @click="month++; getNoOfDays()">
                <svg class="h-6 w-6 text-gray-500 inline-flex" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
                </svg>
              </button>
            </div>
          </div>

          <div class="flex flex-wrap mb-3 -mx-1">
            <template x-for="(day, index) in DAYS" :key="index">
              <div style="width: 14.26%" class="px-1">
                <div x-text="day" class="text-gray-800 font-medium text-center text-xs"></div>
              </div>
            </template>
          </div>

          <div class="flex flex-wrap -mx-1">
            <template x-for="blankday in blankdays">
              <div style="width: 14.28%" class="text-center border p-1 border-transparent text-sm"></div>
            </template>
            <template x-for="(date, dateIndex) in no_of_days" :key="dateIndex">
              <div style="width: 14.28%" class="px-1 mb-1">
                <div @click="getDateValue(date)" x-text="date" class="cursor-pointer text-center text-sm leading-none rounded-full leading-loose transition ease-in-out duration-100" :class="{'bg-blue-500 text-white': isToday(date) == true, 'text-gray-700 hover:bg-blue-200': isToday(date) == false }"></div>
              </div>
            </template>
          </div>
        </div>

      </div>
    </div>

  </div>
</div>

Alpine code

const MONTH_NAMES = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
      const DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

      function app() {
          return {
              showDatepicker: false,
              datepickerValue: '',

              month: '',
              year: '',
              no_of_days: [],
              blankdays: [],
              days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],

              initDate() {
                  let today = new Date();
                  this.month = today.getMonth();
                  this.year = today.getFullYear();
                  this.datepickerValue = new Date(this.year, this.month, today.getDate()).toDateString();
              },

              isToday(date) {
                  const today = new Date();
                  const d = new Date(this.year, this.month, date);

                  return today.toDateString() === d.toDateString() ? true : false;
              },

              getDateValue(date) {
                  let selectedDate = new Date(this.year, this.month, date);
                  this.datepickerValue = selectedDate.toDateString();

                  this.$refs.date.value = selectedDate.getFullYear() +"-"+ ('0'+ selectedDate.getMonth()).slice(-2) +"-"+ ('0' + selectedDate.getDate()).slice(-2);

                  console.log(this.$refs.date.value);

                  this.showDatepicker = false;
              },

              getNoOfDays() {
                  let daysInMonth = new Date(this.year, this.month + 1, 0).getDate();

                  // find where to start calendar day of week
                  let dayOfWeek = new Date(this.year, this.month).getDay();
                  let blankdaysArray = [];
                  for ( var i=1; i <= dayOfWeek; i++) {
                      blankdaysArray.push(i);
                  }

                  let daysArray = [];
                  for ( var i=1; i <= daysInMonth; i++) {
                      daysArray.push(i);
                  }

                  this.blankdays = blankdaysArray;
                  this.no_of_days = daysArray;
              }
          }
      }

https://jsfiddle.net/alr3id/8pLh9cze/

5
  • 1
    I'm getting errors when I change months using the navigational arrows. I can't really solve this issue in the browser right now but I'll circle back to it later today. Love what you've done so far. Commented May 27, 2020 at 16:30
  • What about this date is not defined error? You're calling functions with the parameter date which isn't defined... Commented May 27, 2020 at 16:36
  • @Jacob yeah thats what i was getting, I cant see why as it work fine until you do past December 2020, then when you select a date it selects a date after, but the arrows don't update past December for some reason.. Commented May 28, 2020 at 0:17
  • @Jacob i also notice the errors dont happen when you're within 2020, only when you navigate our of the current year. Commented May 28, 2020 at 0:19
  • In the fiddle, once you click two times (either direction) the error appear. The issue isn't really the date calculation After 2 clicks, you get the error Commented Oct 30, 2020 at 14:01

1 Answer 1

1

when you reach December, you need to set increase the year rather then the month and set the month variable back to 0. Similar thing when you are decreasing the month and you hit January.

<div>
    <button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full" @click="if(month == 0) {month=11;  year--} else {month--}; getNoOfDays()">
        <svg class="h-6 w-6 text-gray-500 inline-flex" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
         </svg>
    </button>
    <button type="button" class="transition ease-in-out duration-100 inline-flex cursor-pointer hover:bg-gray-200 p-1 rounded-full" @click="if (month == 11) {month=0; year++} else {month++}; getNoOfDays()">
        <svg class="h-6 w-6 text-gray-500 inline-flex" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
        </svg>
    </button>
</div>

Something like https://jsfiddle.net/a0726tjw/3/.

It's still returning the odd error about date being undefined which breaks the order of the days when occurs. There's probably another bug somewhere else but I haven't figured out where yet.

Sign up to request clarification or add additional context in comments.

3 Comments

The index on the x-for generating the days of the month was not unique so it was messing up with the previous element instead of regenerating all the elements with new event handlers. There were also a couple of issues with the date methods (getMonth is 0-based so January is 0 and december is 11, getDay is 0-based so Sunday is 0, etc). This snippet should be fully working now: jsfiddle.net/a0726tjw/6
is it possible to set the date to a saved value rather than have it set on today's date?
In the fiddle, once you click two times (either direction) the error appear. The issue isn't really the date calculation After 2 clicks, you get the error – Jan_dh 50 mins ago

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.