Search code examples
javascriptpythonfullcalendarbottle

How to loop and display MySQL dates into FullCalendar


I am using python with bottle framework and JavaScript, and I want to display fetched MySQL dates into FullCalender. I am successfully fetching the data from MySQL, as shown below, but the problem is when I pass the value "dates" to the "start" key, my expectation was to see all the dates in the Callendar, but instead, I am only getting the last date.

Here is my JavaScript code:

<script>
    let calendarElement = document.querySelector("#calendar");
    fetch('/api-fetch-booking_data')
    .then(res => res.json())
    .then(data => {
        data.booking_dates.forEach(element => {
            let dates = element.avalable_dates
            console.log(dates);                
            let calendar = new FullCalendar.Calendar(calendarElement, {
                
                events: [
                    {
                        start: dates,
                    }
                ]
            
            });
        calendar.render();
        })
    })
</script>

These are the dates fetched from MySQL:

enter image description here

This is the UI, as you can see I am only getting the "2022-06-30" date:

enter image description here

I have seen that you could do a for loop like this using flask: enter image description here

but I really don't know how and even if it is bossible to do it with bottle. Hope someone will help me up with this. Thanks in advance.


Solution

  • If you read full documentation for bottle then you should find information how to use for-loops in template in bottle.

    But you send data to JavaScript library FullCalendar and you have to do all in JavaScript.

    You may have to create

    events: [{start: dates[0]}, {start: dates[1]}, ... ]
    

    and this need only JavaScript code, not Python.


    EDIT:

    See documentation for events https://fullcalendar.io/docs/events-array

    var calendar = new Calendar(calendarEl, {
      events: [
        {
          title  : 'event1',
          start  : '2010-01-01'
        },
        {
          title  : 'event2',
          start  : '2010-01-05',
          end    : '2010-01-07'
        },
        {
          title  : 'event3',
          start  : '2010-01-09T12:30:00',
          allDay : false // will make the time show
        }
      ]
    });
    

    But it seems it can get also JSON data which you can format in Python before sending to browser. https://fullcalendar.io/docs/events-json-feed

    var calendar = new Calendar(calendarEl, {
      events: '/link/to/bottle/function'
    });
    

    and this function would have to return JSON with

    [
        {
          title  : 'event1',
          start  : '2010-01-01'
        },
        {
          title  : 'event2',
          start  : '2010-01-05',
          end    : '2010-01-07'
        },
        {
          title  : 'event3',
          start  : '2010-01-09T12:30:00',
          allDay : false // will make the time show
        }
      ]
    

    It seems you already send JSON but you would have to set it as

    events: dates
    

    and in dates you would have to send data formatted as

    [
        {
          title  : 'event1',
          start  : '2010-01-01'
        },
        {
          title  : 'event2',
          start  : '2010-01-05',
          end    : '2010-01-07'
        },
        {
          title  : 'event3',
          start  : '2010-01-09T12:30:00',
          allDay : false // will make the time show
        }
      ]
    

    EDIT:

    Minimal working code.

    It uses only one FullCalendar in JavaScript and it puts all dates from bottle in this FullCalendar.

    Your code uses forEach so it creates many FullCalendar - and it puts every date in separated FullCalendar. But all FullCalendar use the same <div id='calendar'> so finally you see only last FullCalendar with last date.

    from bottle import route, run
    
    @route('/')
    def hello():
        return '''<!DOCTYPE html>
    <html lang='en'>
      <head>
        <meta charset='utf-8' />
        <link href='https://cdn.jsdelivr.net/npm/[email protected]/main.min.css' rel='stylesheet' />
        <script src='https://cdn.jsdelivr.net/npm/[email protected]/main.min.js'></script>
    
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        let calendarElement = document.querySelector("#calendar");
        fetch('/api-fetch-booking_data')
        .then(res => res.json())
        .then(data => {
            console.log(data);
            let calendar = new FullCalendar.Calendar(calendarElement, {
                 events: data
            });
            calendar.render();
        });
    });
    </script>
      </head>
      <body>
        <div id='calendar'></div>
      </body>
    </html>
    '''
    
    @route('/api-fetch-booking_data')
    def data():
        import json
    
        return json.dumps([
                    {
                      "start": "2022-05-01",
                      "title": "Previous month"
                    },
                    {
                      "start": "2022-06-01",
                      "title": "Current month"
                    },
                    {
                      "start": "2022-06-20",
                      "title": "Today"
                    }
                ])
    
    run(host='localhost', port=8080, debug=True)
    

    And the same with events: url instead of fetch()

    EDIT: I added button Refetch Events which reads new data from bottle. In bottle I use random to create random day to see difference. When FullCalendar fetch data from bottle then it automatically adds dates start, end to url /api-fetch-booking_data so bottle could send only events in this range. FullCalendar automatically fetch new events when you change month.

    from bottle import route, request, run
    
    @route('/')
    def hello():
        return '''<!DOCTYPE html>
    <html lang='en'>
      <head>
        <meta charset='utf-8' />
        <link href='https://cdn.jsdelivr.net/npm/[email protected]/main.min.css' rel='stylesheet' />
        <script src='https://cdn.jsdelivr.net/npm/[email protected]/main.min.js'></script>
    
    <script>
    var calendar = "";
    document.addEventListener('DOMContentLoaded', function() {
        let calendarElement = document.querySelector("#calendar");
        calendar = new FullCalendar.Calendar(calendarElement, {
             events: '/api-fetch-booking_data'
        });
        calendar.render();
    });
    </script>
      </head>
      <body>
        <button onclick="calendar.refetchEvents()">Refetch Events</button><br>
        <div id='calendar'></div>
      </body>
    </html>
    '''
    
    @route('/api-fetch-booking_data')
    def data():
        import json
        import random
    
        print('start:', request.query.get('start'))
        print('end  :', request.query.get('end'))
    
        return json.dumps([
                    {
                      "start": "2022-05-01",
                      "title": "Previous month"
                    },
                    {
                      "start": "2022-06-01",
                      "title": "Current month"
                    },
                    {
                      "start": f"2022-06-{random.randint(1,30):02}",
                      "title": "Random day"
                    },
                    {
                      "start": "2022-06-20",
                      "title": "Today"
                    }
                ])
    
    run(host='localhost', port=8080, debug=True)