Using fullcalendar.io with JSONP - javascript

I'm trying to add public holidays to full calendar. http://fullcalendar.io/
var actionUrl = #Html.Raw(Json.Encode(#Url.Action("Calendar", "Lecture")));
$('#fullcalendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
eventTextColor : "Black",
eventSources: [
{
url: actionUrl,
data: function() {
return {
campusIds: getCampusIds(),
lectureRoomIds: getLectureRoomsIds(),
lecturerIds: getLecturerIds(),
eventTypeIds: getEventTypeIds(),
}
},
error: function() {
alert('there was an error while fetching events!');
},
traditional: true
},
{
url: "http://kayaposoft.com/enrico/json/v1.0/?action=getPublicHolidaysForMonth&month=1&year=2013&country=zaf?callback=?",
error: function() {
alert('there was an error while fetching events!');
},
}
],
The first event source works and that fetches json from my mvc controller. The second source however doesn't. I understand I need to use jsonp and I think I need to map the returning data over to something that full calendar understands but I can't get this right. Please assist!
Thanks

Revised answer
I've found a solution. The service you are using for your dates has the API documentation here. The relevant portion:
JSONP
In each operation you can use JSONP like this: Sample URL returning
public holidays in Austria for January 2013:
JSON_URL?action=getPublicHolidaysForMonth&month=1&year=2013&country=aut&jsonp=myfunction
So change callback to jsonp and it should work. Also, it works best with FC if you give a range instead of a month. Your ajax call should look like:
events: function (start, end, timezone, callback) {
console.log(start.format('YYYY-MMM'));
$.ajax({
type: "get",
url: 'http://kayaposoft.com/enrico/json/v1.0/?action=getPublicHolidaysForDateRange&jsonp=?',
data: {
country: "zaf",
fromDate: start.format('DD-MM-YYYY'),
toDate: end.format('DD-MM-YYYY')
},
dataType: 'jsonp',
contentType: 'application/json',
success: function (data) {
var events = [];
$.each(data, function (i, holiday) {
events.push({
start: moment({
year: holiday.date.year,
month: holiday.date.month - 1, //momentjs uses base 0 months
day: holiday.date.day
}),
title: holiday.englishName,
allDay: true
});
});
callback(events);
}
}).fail(function (jqXHR) {
alert("failed to get holidays");
});
Here is a working JSFiddle.
Old answer: (still applicable for non-jsonp servers)
If you are trying to do a cross domain json request (jsonp), the server needs to support it.
JSONP requests are wrapped in script tags and must therefore be valid JS. A literal object is not valid JS (like {a:'b'}).
jQuery handles this by sending a callback function name parameter to the server. It looks like:
callback=jQuery21003313164389692247_1423682275577
The server must wrap the response data in this function like:
jQuery21003313164389692247_1423682275577( {id:"2",name:"me"} );
which is now valid and executable JS.
So, unless that server's API allows for JSONP requests, you cannot do cross domain requests to it. This is a security limitation of web browsers.
As an alternative, you could proxy the data through your server. Have fullcalendar make requests to your server which in turn loads data from the external source and sends it back to the client.

To begin with you need to make a call with valid parameters to the url i.e.
http://kayaposoft.com/enrico/json/v1.0/?action=getPublicHolidaysForMonth&month=1&year=2013&country=eng
This would return data in the following format:
[{"date":{"day":1,"month":1,"year":2015,"dayOfWeek":4},"localName":"New Year's Day","englishName":"New Year's Day"}]
It is then a case of translating that data into the format that expects i.e. EventData.
This is done by iterating over the date objects returned via the json as follows but setting the properties you need (in the below demo I set the title and start):
var items = [];
$.each( json, function( key, val ) {
items.push({ title : val.localName, start : val.date } );
});
This all needs to be wrapped up in a getJson call i.e.
$.getJSON( "http://kayaposoft.com/enrico/json/v1.0/?action=getPublicHolidaysForMonth&month=3&year=2013&country=eng", function( data ) {
$.each( data, function( key, val ) {
items.push({ title : val.localName, start : val.date } );
});
});
You can the set your calendar items as follows (simplified for demo):
$('#calendar').fullCalendar({
events: items
});
jsFiddle
var items = [];
var json = [{"date":{"day":1,"month":1,"year":2015,"dayOfWeek":4},"localName":"New Year's Day","englishName":"New Year's Day"}]
$.each( json, function( key, val ) {
items.push({ title : val.localName, start : val.date } );
});
$('#calendar').fullCalendar({
events: items
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.9.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/2.2.6/fullcalendar.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/2.2.6/fullcalendar.css" rel="stylesheet"/>
<div id='calendar'></div>

Related

Cookies not being sent on cross-sub-domain request on an api call

I have a page stored on https://page.domain.com.
Here, I'm using javascript (mainly Bootstrap) to get data from https://api.domain.com.
The first call, when the page is loaded, is a "sort of" authentication call which return a cookie in the headers:
set-cookie: oauth=emd4YWgybTJobmJnZjVrbXl2ZjdlZThiOzkzczg1YWt2YzNyZW42cjk3M2U4dXlweA==; domain=.domain.com; path=/; expires=Fri, 16 Apr 2021 11:58:07 GMT;
I can see in the developer tools (Chrome) that the cookie is stored correctly.
But then, when I make the next api call (example, filling a dropdown list - bootstrap autocomplete ) the cookie is not in the request.
This was working fine when I was building it in localhost (same "domain", I guess) but now, having the html and the apis running on different domains, it seems cookies are not being shared.
I thought it could be because of the two different domains, but according to the documentation, when a cookie is set to the main domain, all sub-domains should be able to share it. (also, I' including the "withCredentials" flag)
This is the code of the initial call (and setting up the subsequent one):
$.ajax({url: 'https://api.domain.com/get-cookie',
xhrFields: {
withCredentials: true
}
})
.done(function (response) {
$('.selectpicker').selectpicker().ajaxSelectPicker({
ajax: {
// data source
url: 'https://api.domain.com/data.json',
// ajax type
type: 'GET',
// data type
dataType: 'json',
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
// automatically replace it with the value of the search query.
data: {
q: '{{{q}}}'
}
},
// function to preprocess JSON data
preprocessData: function (data) {
var i, l = data.length, array = [];
if (l) {
for (i = 0; i < l; i++) {
array.push($.extend(true, data[i], {
text : data[i].name,
value: data[i].code,
data : {
subtext: data[i].code
}
}));
localStorage.setItem(data[i].code, data[i].name);
}
}
// You must always return a valid array when processing data. The
// data argument passed is a clone and cannot be modified directly.
return array;
}
});
}
);
I'm using AWS API Gateway and Lambda functions, but that should not be relevant...
When taking the url from the selectPicker (eg: https://api.domain.com/data.json ) and putting it directly in the browser I see the cookie being sent.
This seems to indicate the issue might be in the Bootstrap Select component that is not sending the headers correctly.
I'm not sure if I can make it work as expected or I have to find some other alternative.
The solution was to also include the withCredentials on the selector request:
$('.selectpicker').selectpicker().ajaxSelectPicker({
ajax: {
// data source
url: 'https://api.domain.com/data.json',
// ajax type
type: 'GET',
// data type
dataType: 'json',
// Use "{{{q}}}" as a placeholder and Ajax Bootstrap Select will
// automatically replace it with the value of the search query.
data: {
q: '{{{q}}}'
},
xhrFields: {
withCredentials: true
}
},
// function to preprocess JSON data
preprocessData: function (data) {
// ...
}
});
}
);
Thanks #CBroe for the idea in the comments.

Full calendar resource extra params not added

I try to customize the params that send with the events and resources on the fullCalendar library.
I use full calendar version 3.
I can fetch these custom params from a form and assign them to events request.
But the issue is with resources that I use the same code for both but the requested URL for resource breaks and also lost the default start and end prams as well.
The code that I tried:
resources: {
// Resource route to load Instructors.
url: resourcesCallback,
method: 'GET',
data: function() {
var fields = jQuery('.calendar_filter_form').serializeArray();
var datas = {};
jQuery.each(fields, function(index, val) {
/* iterate through array or object */
datas[val.name] = val.value;
});
return datas;
},
failure: function() {
alert('There was an error while fetching instructors!');
},
},
and the event part:
events: {
// Resource route to load Instractors.
url: eventsCallback,
method: 'GET',
data: function() {
var fields = jQuery('.calendar_filter_form').serializeArray();
var data = {};
jQuery.each(fields, function(index, val) {
/* iterate through array or object */
data[val.name] = val.value;
});
return data;
},
failure: function() {
alert('there was an error while fetching events!');
},
}
The generated URL that I get are these:
For events:
Request URL: DOMAIN/load?instractor=&lessonType=&date=&start=2019-07-22T00%3A00%3A00&end=2019-07-23T00%3A00%3A00&_=156377682
For resources:
Request URL: DOMAIN/resources?_=1563776826863
I need to generate the second URL like the first, as you see the code is same but result is different, what is wrong?
The full code if needed:
$('#calendar').fullCalendar({
defaultView: 'agendaDay',
// Active the ajax reload the resources(instructors).
refetchResourcesOnNavigate: true,
// To make the time slot divided in 15mis.
slotDuration: "00:15:00",
displayEventTime : false,
// This define each time slot can get how many part
// of the rows, for example if we set it to "00:01:00"
// then it will divide each row by 15 mins but just show
// the one between one like: 00:15:00 , 00:45:00 , 01:15:00.
slotLabelInterval: "00:01:00",
slotLabelFormat: ['H:mm'],
groupByResource: true,
// To trun of the all day row at the top of calendar.
allDaySlot: false,
groupByDateAndResource: true,
// Settings for manage the calendar header options.
header: {
left: 'prev, today, next',
center: 'title',
right: null,
},
eventRender: function (event, $element) {
// Render the Main content of the events with more details
// and with html tags to be more user friendly.
$element.find('.fc-title').html('<p style="text-align:center">'
+ event.lessonType + ' ~ ' + event.student
+ '<br>' + event.description
+ '<br>' + event.lessonAvailable + '~' + event.nextEvent + '</p>'
);
},
// Define the Calendar column name.
// This part should be dynamic and will
// define by instructor names.
resources: {
// Resource route to load Instructors.
url: resourcesCallback,
method: 'GET',
data: function() {
var fields = jQuery('.calendar_filter_form').serializeArray();
var data = {};
jQuery.each(fields, function(index, val) {
/* iterate through array or object */
data[val.name] = val.value;
});
return data;
},
failure: function() {
alert('There was an error while fetching instructors!');
},
},
// The main part of getting data and manipulate them
// to show those in proper format in the calendar.
// To match with resources here the resourceId should match
// with the ids that provided in the resources.
// Also to get proper location according to time slot
// it need the correct start and end params that should
// be in correct date format like: 2019-07-18T19:30:00.
events: {
// Resource route to load instructors.
url: eventsCallback,
method: 'GET',
data: function() {
var fields = jQuery('.calendar_filter_form').serializeArray();
var datas = {};
jQuery.each(fields, function(index, val) {
/* iterate through array or object */
datas[val.name] = val.value;
});
return datas;
},
failure: function() {
alert('there was an error while fetching events!');
},
}
});
In the meantime, of course, the obvious workaround is to use the resources-as-function pattern instead, then you can construct the AJAX request exactly as you need it.
Thanks, #ADyson.
resources: function(callback){
jQuery('input[name="start"]').val(jQuery('#calendar').fullCalendar('getView').start.format());
jQuery('input[name="end"]').val(jQuery('#calendar').fullCalendar('getView').end.format());
jQuery.ajax({
url: resourcesCallback,
type: 'GET',
dataType: "json",
data: jQuery('.calendar_filter_form').serialize(),
error: function() {
// alert('Oops! Try again.');
},
success: function(response){
callback(response);
}
});
},

ajax request not sending any data ASP.NET MVC project with jQuery

I'm fairly new to asp.net MVC but am baffled as to why my request isn't working.
I'm trying to send an ajax request with jquery as per:
jQuery(function ($) {
var total = 0,
share = $('div.share'),
googlePlusUrl = "https://plusone.google.com/_/+1/fastbutton?url=http://bookboon.com" + $(location).attr('pathname');
setTimeout(function() {
$.ajax({
type: 'GET',
data: "smelly",
traditional: true,
url: share.data('proxy'),
success: function(junk) {
//var $junk = junk.match(regex);
console.log(junk);
},
error: function (xhr, errorText) {
console.log('Error ' + xhr.responseType);
},
});
}, 4000);
And set a line in my RouteConfig as:
routes.MapRoute(null, "services/{site}/proxy", new { controller = "Recommendations", action = "Proxy" });
The markup has a data-attribute value as:
<div class="share" data-proxy="#Url.Action("Proxy", "Recommendations")">
And my Proxy action method starts with:
public ActionResult Proxy(string junk)
The problem is that the junk parameter is always null. I can see in the debug output that the route seems to correctly redirect to this method when the page loads (as per jQuery's document ready function), but I cannot seem to send any data.
I tried sending simple data ("smelly") but I don't receive that neither.
Any suggestions appreciated!
The model binder will be looking for a parameter in the request called junk, however you're sending only a plain string. Try this:
$.ajax({
type: 'GET',
data: { junk: "smelly" }, // <- note the object here
traditional: true,
url: share.data('proxy'),
success: function(junk) {
//var $junk = junk.match(regex);
console.log(junk);
},
error: function (xhr, errorText) {
console.log('Error ' + xhr.responseType);
},
});

Json string not finding controller method

Using a third party plugin for javascript, fullcalendar. One of the options is a dayClick event, which is pretty obvious on what it does. As soon as a day is clicked it performs an action.
So I got ajax in this dayClick function and I'm trying to pass a value to the controller.
$(document).ready(function () {
$('#calendar').fullCalendar({
height: 170,
selectable: true,
editable: true,
defaultView: 'basicWeek',
dayClick: function (date, jsEvent, view) {
$.ajax(
{
url: '#Url.Action("Calendar","Home")',
type: "GET",
data: JSON.stringify({ date: date }),
dataType: "json",
contentType: "application/json; charset=utf-8",
cache: false,
success: function (response) {
$("calendarLoad").append($(response));
$('#myModal').modal();
},
error: function (request, status, error) {
alert(error);
alert(status);
alert(request.responseText);
}
});
}
});
});
If it successfully passes its supposed to write out my partial view. But it doesn't get to this point. I've debugged my controller and the date parameter is null.
[HttpGet]
public ActionResult Calendar(string date)
{
string[] dateSplit = date.Split(new char[] { 'T' });
DateTime objDate = Convert.ToDateTime(dateSplit[0]);
var content = db.Calendars.Where(x => x.startDate == objDate).ToList();
return PartialView(content);
}
I'm using fiddler to monitor the results after using the dayClick function and I see it trying to pass the JSON data but the result is always
No results.
It should just be:
data: { date: date },
without any call to JSON.stringify(). jQuery will convert that object into the appropriate form for the HTTP request. When you pass it a string, it assumes that you've already done the conversion so it just uses the string directly (as you can see in that URL you highlighted in the screenshot).

Get values from object using Backbonejs

i want to get value from this API http://demo82.com/lois/api/get_page/?id=6 using Backbone js. i tried but i don't know how can we get values from object in backbone.
here is my Backbone code
Page = Backbone.Model.extend({
initialize: function() {
this.on('all', function() { console.log(this.get('page')); });
},
url: "http://demo82.com/lois/api/get_page/?id=6",
defaults: {
"id":null,
"title":"",
"content":""
}
});
var page = new Page();
console.log(page.fetch({}));
i am new and try to learn backbonejs please explain what is the better way ? please give me ans using jsfiddle.net.
thanks
Is id always going to be 6? In your code, your model is always getting the 6th thing. If you want a custom url with a get parameter, override url as a function:
url: function() {
id = this.get("id");
return "loispage/api/get_page/?id=" + id
}
Better yet, if you have control over the server side and can do something a little more RESTful with a page entity -- simply set urlRoot
urlRoot: "loispage/api/page/"
and fetch will automatically do an HTTP get from
"http://.../loispage/api/page/<id>
It looks like a context problem (this doesn't refer to the model in on's callback). You can fix this by specifying the context:
this.on('all',
function() { console.log(this.get('pagel')); },
this
);
Edit
There's also a cross-domain issue. You'll need to use a JSONP request for this by overriding sync and parse. (I adapted the following code from this example.)
var Page= Backbone.Model.extend({
// override backbone synch to force a jsonp call
sync: function(method, model, options) {
// Default JSON-request options.
var params = _.extend({
type: 'GET',
dataType: 'jsonp',
url: model.url(),
processData: false
}, options);
// Make the request.
return $.ajax(params);
},
parse: function(response) {
// parse can be invoked for fetch and save, in case of save it can be undefined so check before using
if (response) {
console.log(JSON.stringify(response));
// here you write code to parse the model data returned and return it as a js object
// of attributeName: attributeValue
return { status: response.status }; // just an example
}
},
Here's a JSFiddle demo.

Categories

Resources