0

I'm hoping that someone can please help with FullCalendar (v4) not loading events when using the Json option. It works fine when the same data is hard coded as an event.

The Json produced is valid - i.e. it validates with https://jsoncompare.com

I've spent an enormous amount of time trying to figure this out myself and I've hit a wall - so time to ask for help.

I've tried using the built in Net Json serializer - but this produces the wrong date format, so I've also tried newtonsoft Json.net, which does produce the correct date format for FullCallendar but still will not load events.

There are no JS console errors when using the JSON, it simply does not load into the calendar. The JSON is coming from the same domain (i.e. not affected by cross domain issue).

Any help/advice would be most welcome, thank you.

THIS WORKS PERFECTLY, WHEN THE EVENTS ARE HARDCODED:

var calendar = new FullCalendar.Calendar(calendarEl,
                {
                    plugins: ['interaction', 'dayGrid', 'timeGrid'],
                    defaultDate: new Date(),
                    defaultView: 'timeGridWeek',
                    minTime: '07:00:00',
                    maxTime: '22:00:00',
                    timeZone: 'local',
                    header: {
                        left: 'prev,next today',
                        center: 'title',
                        right: 'timeGridDay,timeGridWeek,dayGridMonth'
                    },
                    events: [ //hardcoded events load just fine
                            {
                                id: '12',
                                title: 'Event Name',
                                start: '2019-08-28T08:00:00',
                                end: '2019-08-28T08:30:00'
                            }
                        ]

                });

            calendar.render();

        }

WHEN USING THE JSON OPTION, IT DOES NOT WORK:

//JSON provided events do not load
events: {
          url:'/CourseTimetable/GetAllEventsAsJson' 
         }

ALTERNATIVE WAY OF PROVIDING FEED (without braces and "url:" prefix):

events:'/CourseTimetable/GetAllEventsAsJson' 

THE URL WORKS FINE - validates as JSON - AND DOES NOT GENERATE ANY ERRORS - IT PRODUCES:

"[{\"id\":12,\"title\":\"Event 1\",\"start\":\"2019-08-29T08:00:00\",\"end\":\"2019-08-29T08:30:00\"}]"

HEADER and cors info:

Content-Type: application/json; charset=utf-8
Referer: http://localhost:54928/CourseTimetable
Request Method: GET
Status Code: 200 OK

Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

Thanks in advance for any help/advice :)

Here are the two alternative controller versions (with standard .net and then with json.net)

Standard .net

 public JsonResult GetAllEventsAsJson(DateTime? start = null, DateTime? end = null)
        {

            var events = db.CourseTimetables.Where(p => p.StartTime >= start && p.EndTime <= end)
                .Select(s => new
                {
                    id = s.Id,
                    title = s.Title,
                    start = s.StartTime,
                    end = s.EndTime
                }).ToList();

            //using built in .NET serialiser
            return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
        }

OUTPUT FROM ABOVE ACTION (main difference being the outputted dates and escaping):

[{"id":12,"title":"Event 1","start":"\/Date(1567062000000)\/","end":"\/Date(1567063800000)\/"},{"id":13,"title":"Event 2","start":"\/Date(1567148400000)\/","end":"\/Date(1567150200000)\/"}]

Json.Net version

 public ActionResult GetAllEventsAsJson(DateTime? start = null, DateTime? end = null)
        {

            var events = db.CourseTimetables.Where(p => p.StartTime >= start && p.EndTime <= end)
                .Select(s => new
                {
                    id = s.Id,
                    title = s.Title,
                    start = s.StartTime,
                    end = s.EndTime
                }).ToList();

            //USING JSON.NET
            string jsonData = JsonConvert.SerializeObject(events);
            return Json(jsonData, JsonRequestBehavior.AllowGet);
        }

OUTPUT FROM ABOVE ACTION (dates are in correct iso format with this):

"[{\"id\":12,\"title\":\"Event 1\",\"start\":\"2019-08-29T08:00:00\",\"end\":\"2019-08-29T08:30:00\"},{\"id\":13,\"title\":\"Event 2\",\"start\":\"2019-08-30T08:00:00\",\"end\":\"2019-08-30T08:30:00\"}]"
ADyson
  • 57,178
  • 14
  • 51
  • 63
MRB
  • 43
  • 1
  • 6
  • What does the `/CourseTimetable/GetAllEventsAsJson` look like? – Halden Collier Aug 30 '19 at 10:33
  • Thanks for the reply - I will update the question to include bother versions of the controller (standard .net and also json.net version), although the surely it's the resulting json output that matters? – MRB Aug 30 '19 at 12:26

1 Answers1

0

This format: "[{\"id\":12,\"title\":\"Event 1\",\"start\":\ ...etc is the problem. You're double-serialising the data. See those outer quote marks (") and slashes \? The outer quote marks indicate that you are returning a simple string as the response (which is valid JSON, but will be treated as plain text by the parser), and the slashes are the result of having to escape the quote marks within the string. Thus the inner data, while it looks like JSON, is not treated as JSON by the client-side parser. Instead the whole thing is just treated as one big string, with no objects, properties etc within it.

In ASP.NET MVC, return Json... expects you to supply it with an object. It will then automatically serialise that to JSON for you. You don't need to serialise it before you pass it in. Just remove that code and send events directly to the Json() method:

public ActionResult GetAllEventsAsJson(DateTime? start = null, DateTime? end = null)
{
        var events = db.CourseTimetables.Where(p => p.StartTime >= start && p.EndTime <= end)
            .Select(s => new
            {
                id = s.Id,
                title = s.Title,
                start = s.StartTime,
                end = s.EndTime
            }).ToList();

        return Json(events, JsonRequestBehavior.AllowGet);
    }

P.S. What version of MVC are you using? The more recent, supported versions use JSON.NET as the default serialiser anyway, so there should be no reason to have to do it manually. If you have an older version of MVC (which it looks like you might have since it's producing those odd date formats e.g. Date(1567062000000)\) and cannot upgrade for some reason, there are ways to make it use JSON.NET by default. Alternatively, you could do the serialisation yourself using JSON.NET, and then just return a plain string from your action method.

P.P.S. Another alternative to the above is to use the momentJS plugin in fullCalendar which then allows you to use momentJS to parse your dates - and momentJS includes the ability to parse ASP.NET's old date format.

ADyson
  • 57,178
  • 14
  • 51
  • 63
  • That makes sense, thank you so much for a really helpful answer. It's not working just yet (after making the changes to the Return object) but the quotes have gone. I think the problem now is that it's reverted to using the odd dates again, but at least I can look at making it use the json.net library. It's MVC 5 by the way and it does have json.net by default, it's just not using it for some reason - again I will look into the other link you provided. Thank you – MRB Aug 30 '19 at 14:33
  • Actually after a bit more googling I noticed it may still be the case in MVC 5 that it might use the old serialiser. Web API always uses JSON.NET but MVC may not do. [this question](https://stackoverflow.com/questions/14591750/setting-the-default-json-serializer-in-asp-net-mvc) discusses the ways you can configure newer versions of MVC to make sure it always uses JSON.NET. – ADyson Aug 30 '19 at 14:37
  • Thank you again, very helpful. – MRB Aug 30 '19 at 15:52