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\"}]"
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.
Related
I am using fullCalendar in my MVC project. I downloaded fullCalendar from Nuget but it doesn't display my data on the calendar. I can get my data but it is not displaying.
What is going wrong in my code?
MVC action method:
public JsonResult GetEvents()
{
dbContext = new Context();
var events = dbContext.Schedule.ToList();
return new JsonResult { Data = events, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
View:
I think the GenerateCalendar function is not working.
<link href="~/Content/fullcalendar.min.css" rel="stylesheet" />
<script src="~/Content/PanelJS/jquery.min.js"></script>
<script src="~/Content/PanelJS/moment.min.js"></script>
<script src="~/Scripts/fullcalendar.min.js"></script>
<script>
$(document).ready(function () {
var events = [];
$.ajax({
type: "GET",
url:"#Url.Action("GetEvents","Schedule")",
success: function (data) {
$.each(data,function(i,v)
{
events.push({
title: v.Name,
start: v.Date,
end: v.EndDate,
location:v.Location
});
console.log(events);
})
GenerateCalendar(events);
},
error:function(error)
{
alert('Error');
}
});
function GenerateCalendar(events)
{
$('#calendar').fullCalendar('destroy');
$('#calendar').fullCalendar(
{
contentHeight: 400,
defaultDate: new Date(),
color:'lightBlue',
timeFormat: 'h(:mm)a',
header: {
left: 'prev,next today',
center: 'title',
right:'month,basicWeek,basicDay,agenda'
},
eventLimit: true,
eventColor: '#378006',
events:events
})
}
});
</script>
Console result ;
end: "10/05/2018 "location: "Chicago" start: "09/05/2018" title: "MyEvent"
From the console output it looks like your dates are being supplied as strings in an ambiguous format. fullCalendar / momentJS will not understand that without being explicitly told what you format is being used. It could be dd/mm/yyyy or mm/dd/yyyy. There is no way for the parser to know what to do with it.
Therefore fullCalendar will not be able to use this data as an event, because it doesn't understand the start and end dates.
The date and time formats accepted by fullCalendar are the same as those accepted by momentJS (since it uses momentJS to work with dates). This is documented here: https://fullcalendar.io/docs/moment and in more detail here: http://momentjs.com/docs/#/parsing/
Therefor, you can either
1) (recommended) Re-write your server-side code so that it returns dates in ISO format. Generally if you are using DateTime objects in your C# code, then the .NET JSON serialiser will do that for you automatically. Since you're directly serialising the result of an Entity Framework query into JSON, then I would suspect that the Date and EndDate properties of your Schedule class are strings rather than DateTimes, which in turn means that you may be storing dates as strings within your database. If so, that is a bad practice which you should fix immediately by storing dates as datetime columns. Dates are not strings, they are dates. What you see on screen (e.g. 09/05/2018) is merely one of many possible representations of that date in a human-readable form. It is not a good format for actually storing the date information.
OR
2) (alternative) If that's not the case, or not possible for some reason, then tell momentJS to parse the dates according to the format you're supplying and then pass the data to fullCalendar as a moment object, e.g.
events.push({
title: v.Name,
start: moment(v.Date, "DD/MM/YYYY"),
end: moment(v.EndDate, "DD/MM/YYYY"),
location: v.Location
});
In-depth documentation of the format-specific parsing functionality in momentJS can be found here: http://momentjs.com/docs/#/parsing/string-format/
I am using Angular4 with TypeScript version 2.2.2
My web app is running fine when I call JSON with Filters but my NativeScript app fails when I call the Filter Values as an Object but works fine when I call filter values as a string.
Error Response with status: 200 for URL: null
THIS WORKS
https://domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter=text&search=upcoming
If the filter value and search value is STRING it works whereas if they are objects as below, it does not work
THIS DOES NOT WORK
https://api.domainname.com/api/v1/searchevents?token=057001a78b8a7e5f38aaf8a682c05c414de4eb20&filter={"limit":"12","skip":"0"}&search={"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}
The Code I used is below
getData(serverUrl, type, skip_limit) {
console.log(serverUrl);
let headers = this.createRequestHeader();
let token_value = localStorage.getItem('access_token')
let url;
var filter;
filter = '{"limit":"10","skip":"0"}'
url = this.apiUrl + serverUrl + '?token=' + token_value + '&filter=' + filter
return this.http.get(url, { headers: headers })
.map(res => res.json());
}
The URL as formed above for the API is fine and works fine. Yet the error comes Error Response with status: 200 for URL: null
CAN ANYONE HELP ME SOLVE THIS?
Looks like the issue is the "filter" values are of different type and from what you mentioned as what worked, your service is expecting a string and not an object/array. So it fails to send the proper response when it gets one. With an object in the URL, you may have to rewrite the service to read it as an object (parse the two attributes and get them individually)
To make it simple, you can make these two as two different variables in the URL. like below,
https://api.domainName.in/api/v1/oauth/token?limit=10&skip=0
Be more precise in whats happening in your question,
1) Log the exact URL and post it in the question. No one can guess what goes in "text" in your first URL.
2) Your URL which you mentioned as worked have "token" as part of path, but in the code, its a variable which will have a dynamic value from "token_value".
3) Post your service code. Especially the signature and input parsing part.
Got the solution:
All you have to do is encode the Filter and Search Parameters if it is an Object or Array using Typescript encodeURI()
var filter = '{"limit":"12","skip":"0"}'
var search = '{"search":"","latitude":"","longitude":"","categories":"","address":"","type":"upcoming"}'
var encoded_filter = encodeURI(filter);
var encoded_search = encodeURI(search);
url = this.apiUrl+serverUrl+'?token='+token_value+'&filter='+encoded_filter+'&search='+encoded_search
I have a Visual Studio (2015) project that includes a client part (Xamarin.Forms PCL) and a web service part ( WCF Rest). The web services use edmx to communicate with the database ( SQL Server 2016). JSON is used to exchange the data.
I'm new to creating/consuming WCF Rest services. I have no issue using the GET method but I'm stuck with an issue with a POST method.
This method is part of a service that works well: no issue for a GET based method. It works well when I test it from a URL or from my client ( PCL Xamarin.Forms).
The POST method (my first ever) is a bit more problematic.
It's supposed to create a new record in a table in SQL Server (2016).
When I use Postman (https://www.getpostman.com/) to test it, it already has an issue: it creates a record in the table but the object has two dates and the two dates are replaced by 1970-01-01.
When I use my client to contact the web service:I get 'Bad Request'.
I looked for a solution and found that instead of placing the Datetime value, it was best to place the number of milliseconds from 1970-01-01.
I used this advice in Postman and noticed the creation of a new line worked fine.
Body of the Postman request :
{
"Reservation_Utilisateur_Id" : "4",
"Reservation_Velo_Id" : "2",
"Reservation_DateDebut" : "\/Date(1245398693390)\/",
"Reservation_PeriodeDebut" : "matin",
"Reservation_DateFin" :"\/Date(1245398693390)\/",
"Reservation_PeriodeFin" : "matin"
}
Now, I'd like to know how to get that object to send to the server . How can my object be serialized like above?
I looked for a solution unsuccessfully.
I keep on getting "There was an error deserializing the object of type BikeSharingService.Reservation. DateTime content '2016-08-22T00:00:00+02:00' does not start with '/Date(' and end with ')/' as required for JSON."
Could someone please give the newbie that I am an explanation and maybe some code that works?
Here is my code:
My contract:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "create",
ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
Reservation create(Reservation reservation);
The service method:
public Reservation create(Reservation reservation)
{
using (MyEntities bse = new MyEntities())
{
Reservation re = new Reservation
{
Reservation_Utilisateur_Id = reservation.Reservation_Utilisateur_Id,
Reservation_Velo_Id = reservation.Reservation_Velo_Id,
Reservation_DateDebut = reservation.Reservation_DateDebut,
Reservation_PeriodeDebut = reservation.Reservation_PeriodeDebut,
Reservation_DateFin = reservation.Reservation_DateFin,
Reservation_PeriodeFin = reservation.Reservation_PeriodeFin,
Reservation_DemandeRecupDomCli = reservation.Reservation_DemandeRecupDomCli
};
bse.Reservations.Add(re);
bse.SaveChanges();
return re;
}
}
On the client side :
const string Url1 = "http://localhost:51843/ServiceReservation.svc/create";
public async Task<Reservation> create(Reservation reservation)
{
string json = JsonConvert.SerializeObject(reservation);
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var response = await client.PostAsync(Url1,
new StringContent(
json,
Encoding.UTF8, "application/json"));
return JsonConvert.DeserializeObject<Reservation>(
await response.Content.ReadAsStringAsync());
}
Then calling the method on the client side :
Reservation re =new Reservation();
re.Reservation_Utilisateur_Id = 4;
re.Reservation_Velo_Id = 2;
re.Reservation_DateDebut = DateTime.Now.Date;
re.Reservation_PeriodeDebut = "matin";
re.Reservation_DateFin = DateTime.Now.Date;
re.Reservation_PeriodeFin = "matin";
re.Reservation_DemandeRecupDomCli = 1;
Reservation resultat = await reManager.create(re);
What I get :
False Bad Request Method: POST, RequestUri:
'http://localhost:51843/ServiceReservation.svc /create', Version: 2.0,
Content: System.Net.Http.StringContent, Headers: { Accept:
application/json Content-Type: application/json; charset=utf-8
Content-Length: 407 } BadRequest
1.1
There was an error deserializing the object of type
BikeSharingService.Reservation. DateTime content
'2016-08-22T00:00:00+02:00' does not start with '/Date(' and end with
')/' as required for JSON.
[Promoted from a comment]
Json doesn't define a standard date format, but it's worth noting that Json.Net (which is used by most of the web-facing parts of the .Net framework) supports multiple formats out of the box (and even custom ones).
If you can decide on a standard which works for all your clients, you can configure the Json (en/de)coding in .Net to use it natively.
See http://newtonsoft.com/json/help/html/datesinjson.htm for more information and details on how to specify a date format handler.
[Example code from link]
public void WriteJsonDates()
{
LogEntry entry = new LogEntry
{
LogDate = new DateTime(2009, 2, 15, 0, 0, 0, DateTimeKind.Utc),
Details = "Application started."
};
// default as of Json.NET 4.5
string isoJson = JsonConvert.SerializeObject(entry);
// {"Details":"Application started.","LogDate":"2009-02-15T00:00:00Z"}
JsonSerializerSettings microsoftDateFormatSettings = new JsonSerializerSettings
{
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
};
string microsoftJson = JsonConvert.SerializeObject(entry, microsoftDateFormatSettings);
// {"Details":"Application started.","LogDate":"\/Date(1234656000000)\/"}
string javascriptJson = JsonConvert.SerializeObject(entry, new JavaScriptDateTimeConverter());
// {"Details":"Application started.","LogDate":new Date(1234656000000)}
}
What you are trying to use is the Epoch DateTime or Unix DateTime.
To convert the DateTime object to epoch datetime you can create a helper method. It is either milliseconds or seconds from 1/1/1970.
Also if needed you can use the Noda DateTime instead of the .NET which has the method in it to convert.
You can create a New class with string data type for DateTime and have a Casting specified. Or you can write your on custom Serialize method.
By default DateTime format after serialization would be ISO 8601 Format.
Code to convert to Unix or Epoch Date time :
private static readonly DateTime EpochDateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long ConvertDateTimeToUnixTime(DateTime date, bool isDatarequiredInMilliSeconds = false, DateTimeKind dateTimeKind = DateTimeKind.Local)
{
return Convert.ToInt64((DateTime.SpecifyKind(date.Value, dateTimeKind).ToUniversalTime() - EpochDateTime).TotalSeconds) * (isDatarequiredInMilliSeconds ? 1000 : 1);
}
You can use the following if you need to convert back(source):
var milliseconds = "/Date(1245398693390)/".replace(/\/Date\((-?\d+)\)\//, '$1');
var actualDate = new Date(parseInt(milliseconds));
I have a rest service for which I am sending the Json data as ["1","2","3"](list of strings) which is working fine in firefox rest client plugin, but while sending the data in application the structure is {"0":"1","1":"2","2":"3"} format, and I am not able to pass the data, how to convert the {"0":"1","1":"2","2":"3"} to ["1","2","3"] so that I can send the data through application, any help would be greatly appreciated.
If the format of the json is { "index" : "value" }, is what I'm seeing in {"0":"1","1":"2","2":"3"}, then we can take advantage of that information and you can do this:
var myObj = {"0":"1","1":"2","2":"3"};
var convertToList = function(object) {
var i = 0;
var list = [];
while(object.hasOwnProperty(i)) { // check if value exists for index i
list.push(object[i]); // add value into list
i++; // increment index
}
return list;
};
var result = convertToList(myObj); // result: ["1", "2", "3"]
See fiddle: http://jsfiddle.net/amyamy86/NzudC/
Use a fake index to "iterate" through the list. Keep in mind that this won't work if there is a break in the indices, can't be this: {"0":"1","2":"3"}
You need to parse out the json back into a javascript object. There are parsing tools in the later iterations of dojo as one of the other contributors already pointed out, however most browsers support JSON.parse(), which is defined in ECMA-262 5th Edition (the specification that JS is based on). Its usage is:
var str = your_incoming_json_string,
// here is the line ...
obj = JSON.parse(string);
// DEBUG: pump it out to console to see what it looks like
a.forEach(function(entry) {
console.log(entry);
});
For the browsers that don't support JSON.parse() you can implement it using json2.js, but since you are actually using dojo, then dojo.fromJson() is your way to go. Dojo takes care of browser independence for you.
var str = your_incoming_json_string,
// here is the line ...
obj = dojo.fromJson(str);
// DEBUG: pump it out to console to see what it looks like
a.forEach(function(entry) {
console.log(entry);
});
If you're using an AMD version of Dojo then you will need to go back to the Dojo documentation and look at dojo/_base/json examples on the dojo.fromJson page.
I have just started getting familiar with dojo and creating widgets and have a web UI which I would like to now populate with data. My question is merely to get some references or ideas on how to do this. My databases are all sql server 2008 and I usually work with microsoft.net. I thought that I would probably have to create a service that calls the sql queries and converts the results into json and feed that into the widgets whether it be the datagrid or charts. Just not sure how to do this and if it is indeed possible to do that. Any ideas appreciated.
EDIT:
store = new dojo.data.ItemFileWriteStore({
url: "hof-batting.json"
});
ngrid = new dojox.grid.DataGrid({
store: store,
id: 'ngrid',
structure: [
{ name: "Search Term", field: "searchterm", width: "10%" },
{ name: "Import Date", field: "importDate", width: "10%" }
]
}, "grid");
ngrid.startup();
I want to add data returned from my web service to this datagrid and use the same principle to add data to a chart.
Your describe exactly what you need to do.
We use C# to query our database to get the data and then convert it to json. We use multiple techniques right now for json serialization. I would recommend using JSON.NET. It is what the .NET MVC team is going to use. I would not use the DataContractSerialization that is currently part of .NET.
http://json.codeplex.com/
We sometimes put JSON right on the page and the javascript accesses it as a page variable. Other times we call services in .NET. We use WCF and we have also used an .ashx file to give the web client json data.
The structure of the json will be the contract between your dojo widgets and web server. I would use what the chart widgets or store will need to start the process of defining the contract.
EDIT
WCF Interface
[OperationContract]
[WebInvoke(Method="POST", UriTemplate = "/data/{service}/",
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
String RetrieveData(string service, Stream streamdata);
The implementation returns a string that is the json. This gets sent to the browser as json, but it's wrapped by .NET by an xml node. I have a utility function that cleans it.
MyUtil._xmlPrefix =
'<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">';
MyUtil._xmlPostfix = '</string>';
MyUtil.CleanJsonResponse = function(data) {
// summary:
// a method that cleans a .NET response and converts it
// to a javascript object with the JSON.
// The .NET framework, doesn't easily allow for custom serialization,
// so the results are shipped as a string and we need to remove the
// crap that Microsoft adds to the response.
var d = data;
if (d.startsWith(MyUtil._xmlPrefix)) {
d = d.substring(MyUtil._xmlPrefix.length);
}
if (d.endsWith(MyUtil._xmlPostfix)) {
d = d.substring(0, d.length - MyUtil._xmlPostfix.length);
}
return dojo.fromJson(d);
};
// utility methods I have added to string
String.prototype.startsWith = function(str) {
return this.slice(0, str.length) == str;
};
String.prototype.endsWith = function(str) {
return this.slice(-str.length) == str;
};