date-formattingalpine.jssession-storagepersistflatpickr

Flatpickr Date Range Session Storage in ISO format with AlpineJS Persist


I am using AplineJS Persist to store the date range of Flatpickr to session storage. This is my Flatpickr code:

            <div x-data="{
                thePicker: null,
                init() {
                    this.thePicker = flatpickr(this.$refs.picker, {
                        mode: 'range',
                        minDate: 'today',
                        inline: false,
                        dateFormat: 'M j',
                        showMonths: 2,
                        defaultDate: this.dateRange,
                        onChange: (selectedDates) => {this.dateRange = [...selectedDates];}
                    });
                },
            }"
            >
                <div class="flex items-center flex-1 gap-2 overflow-hidden border border-gray-500 rounded-lg">
                    <input type="text"
                        x-ref="picker"
                        placeholder="Add dates"
                        class="p-0 py-4 placeholder-gray-600 border-0 bg-none focus:ring-0"
                    >
                </div>
            </div>

And here is my x-data to store it with persist:

dateRange: $persist([]).using(sessionStorage).as('_x_range'),

The problem I am having is that the date range is being stored in ISO format, like so:

["2024-02-19T07:00:00.000Z","2024-02-22T07:00:00.000Z"]

And I am really struggling to understand how either store it as M j or format it back to M j from ISO.

In this case, I would be totally fine with storing it, for example:

Jan 1 to Jan 8, 2024

But then when displaying the date on the front-end via x-text or x-html, remove the year:

Jan 1 to Jan 8


Solution

  • It's not advisable to alter the stored format.

    You can use onChange and onReady events to replace the displayed format:

    init() {
    
        const rewriteRange = (selectedDates, dateStr, instance) => {
            const year0 = selectedDates[0]?.getFullYear();
            if (selectedDates[0]  &&  year0 === selectedDates[1]?.getFullYear())
                instance.element.value = dateStr.replaceAll (' ' + year0, '');
        };
    
        this.thePicker = flatpickr(this.$refs.picker, {
            mode: 'range',
            inline: false,
            dateFormat: 'M j Y',
            showMonths: 2,
            defaultDate: this.dateRange,
    
            onChange: (selectedDates, dateStr, instance) => {
                this.dateRange = [...selectedDates];
                rewriteRange (selectedDates, dateStr, instance);
            },
    
            onReady: (selectedDates, dateStr, instance) => {
                rewriteRange (selectedDates, dateStr, instance);
            }
        });
    }
    

    This way the year is only displayed when the interval straddles two years (note the dateformat).

    To display the range somewhere else in your own format, you can manupulate the dates e.g. using toLocaleDateString:

    <div x-data="{
    
       .....
    
       init() {
    
          .....
    
       },
    
       displayRange() {
           return new Date(this.dateRange[0]).toLocaleDateString('en-us',{day: 'numeric', month: 'short'}) +
                  ' to ' +
                  new Date(this.dateRange[1]).toLocaleDateString('en-us',{day: 'numeric', month: 'short'}) +
                  ', ' +  new Date(this.dateRange[0]).getFullYear()
       }
    }">
    
       <!-- ..... -->
    
       <div x-text="displayRange"
            x-show="dateRange[0]  &&  dateRange[1]"
       > </div> 
    
    </div> 
    

    Here displayRange() is a simplified example of how to compose your format