My problem is when event is successfully added, it shows on the screen but id is not included and thus if we want to edit an event that we just add without refreshing the page, error will appear which says id doesn't match.
Add function looks like this.
function registSchedule() {
// 開始終了日付の調整
var startYmd = moment(formatNengappi($('#inputYmdFrom').val() + "00時00分00", 1));
var endYmd = moment(formatNengappi($('#inputYmdTo').val() + "00時00分00", 1));
var allDayCheck = $('#allDayCheck').prop("checked");
if (!allDayCheck) {
startYmd = moment(formatNengappi($('#inputYmdHmFrom').val() + "00", 1));
endYmd = moment(formatNengappi($('#inputYmdHmTo').val() + "00", 1));
}
if (endYmd.diff(startYmd, 'days') > 0) {
endYmd = endYmd.add(+1, "days");
}
//非同期でサーバーにリクエストを送信
var EventData = {
id: $("#scheduleId").val(),
title: $('#inputTitle').val(),
start: startYmd.format("YYYY-MM-DDTHH:mm:ss"),
end: endYmd.format("YYYY-MM-DDTHH:mm:ss"),
allDay: allDayCheck,
};
sendAjaxRequest("add_event", EventData);
}
sendAjaxRequest looks like this.
function sendAjaxRequest(method, EventData) {
var cal = $("#calendar").fullCalendar("getView");
EventData.searchStart = cal.start;
EventData.searchEnd = cal.end;
// 処理名を設定
var methodName = "登録";
if (method == "update") {
methodName = "更新"
} else if (method == "remove") {
methodName = "削除"
}
$.ajax({
url: "/fullcalendar/" + method,
type: "GET",
data: {'title': EventData.title, 'start': EventData.start, 'end': EventData.end,'id': EventData.id,'allDay':EventData.allDay},
success: function(data) {
// カレンダー再描画
$('#calendar').fullCalendar( 'removeEvents', EventData.id );
$('#calendar').fullCalendar('renderEvent', EventData);
$('#inputScheduleForm').modal('hide');
alert("予定を" + methodName + "しました。");
console.log(EventData)
},
error: function(data) {
alert("予定の" + methodName + "に失敗しました。");
}
});
$('#calendar').fullCalendar('unselect');
}
views.py looks like this.
def add_event(request):
title = request.GET.get("title", None)
start = request.GET.get("start", None)
end = request.GET.get("end", None)
event = Events(title=str(title), start=start, end=end)
event.save()
data = {}
return JsonResponse(data)
result from console.log(EventData) after I clicked add button:
{id: "", title: "abcccc", start: "2020-08-21T00:00:00", end: "2020-08-21T00:00:00", allDay: true, …}
What should I add in the success: function(data) {} part to make sure after I add the event, I don't have to refresh the button to create a new id?
Any idea anyone?
I am building a AJAX live search page.So far everything is working as intended, but I have noticed that I am doing TONS of AJAX calls.
I know where and why this is happening, but I cannot find a way to stop these AJAX calls from happening.
I will try to give a quick explanation and paste the code below afterwards.
On the left side of the page I have a bunch of filters (e.g. location, radius, interests, engagements, daterange, ...). Each and every one of them has an event listener on them (eg changed). When one of those listeners is triggered, I update my query parameters and request the results via AJAX.
Now the problem occurs when for example someone has selected 10 interests (there are 36 of them), and then he shares the URL, it would look like this:
http://localhost/codeigniter/nl-be/sociale-teambuildings/zoeken?locations=&distance=0&minemployees=0&maxemployees=1000&minprice=0&maxprice=50000&interests=1%3B2%3B3%3B4%3B5%3B6%3B7%3B8%3B9%3B10&sdgs=&startdate=2018-12-03&enddate=2019-12-03&engagements=
Now first off, I will say that I am using iCheck.js for my checkboxes. This means that there's a check on the 'ifChecked' event.
Since the list contains 10 interest entries, the 'ifChecked' event will be fired 10 times, and thus resulting in 10 AJAX request. Now consider this in combination with 5 SDG's, 2 engagaments, 3 locations, ... and I end up with a ton of AJAX requests.
As well while removing all of my interests at the same time (there's a 'remove' link), it will fire the 'ifUnchecked' event 10 times, and thus again perform 10 AJAX requests.
This is my full JS code, i've tried creating a jsfiddle with the HTML and all, but the code is a bit intermingled with CodeIgniter framework and hard to place in there. But the JS code is enough to get the picture across.
//Set vars available to entire scope for filtering
var searchLocation = null;
var searchRadius = 0;
var searchMin = 0;
var searchMax = 1000;
var searchMinPrice = 0;
var searchMaxPrice = 50000;
var searchSelectedInterests = [];
var searchSelectedSdgs = [];
var searchStartDate = moment().format('YYYY-MM-DD');
var searchEndDate = moment().add(1, 'years').format('YYYY-MM-DD');
var searchSelectedEngagements = [];
var getUrl = window.location;
var baseUrl = getUrl .protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1];
$(document).ready(function(){
'use strict';
// Square Checkbox & Radio
$('.skin-square input').iCheck({
checkboxClass: 'icheckbox_square-blue'
});
$('.searchinterests input').on('ifChecked', function(event) {
var interestid = event.target.value;
searchSelectedInterests.push(interestid);
updateURLParameters();
performSearch();
});
$('.searchinterests input').on('ifUnchecked', function(event) {
var interestid = event.target.value;
var arrayPos = $.inArray(interestid, searchSelectedInterests);
if (arrayPos > -1) {
searchSelectedInterests.splice(arrayPos, 1);
}
performSearch();
});
$('.searchsdgs input').on('ifChecked', function(event) {
var sdgid = event.target.value;
searchSelectedSdgs.push(sdgid);
updateURLParameters();
performSearch();
});
$('.searchsdgs input').on('ifUnchecked', function(event) {
var sdgid = event.target.value;
var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
if (arrayPos > -1) {
searchSelectedSdgs.splice(arrayPos, 1);
}
performSearch();
});
$('.searchengagements input').on('ifChecked', function(event) {
var social_engagement_id = event.target.value;
searchSelectedEngagements.push(social_engagement_id);
updateURLParameters();
performSearch();
});
$('.searchengagements input').on('ifUnchecked', function(event) {
var social_engagement_id = event.target.value;
var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
if (arrayPos > -1) {
searchSelectedEngagements.splice(arrayPos, 1);
}
performSearch();
});
var searchLocationSelect = $('.stb-search-location');
var radiusSlider = document.getElementById('radius-slider');
var minMaxSlider = document.getElementById('min-max-slider');
var priceSlider = document.getElementById('price-slider');
var daterangepicker = $('#searchdaterange');
var curr_lang = $('#curr_lang').val();
switch(curr_lang) {
case 'nl':
moment.locale('nl');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Volgende week': [moment(), moment().add(1, 'weeks')],
'Volgende maand': [moment(), moment().add(1, 'months')],
'Volgende 3 maanden': [moment(), moment().add(3, 'months')],
'Volgende 6 maanden': [moment(), moment().add(6, 'months')],
'Volgend jaar': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Vrije keuze",
"format": "DD-MM-YYYY"
}
});
break;
case 'en':
moment.locale('en');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Next week': [moment(), moment().add(1, 'weeks')],
'Next month': [moment(), moment().add(1, 'months')],
'Next 3 months': [moment(), moment().add(3, 'months')],
'Next 6 months': [moment(), moment().add(6, 'months')],
'Next year': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Free choice",
"format": "DD-MM-YYYY"
}
});
break;
case 'fr':
moment.locale('fr');
daterangepicker.daterangepicker({
minDate: moment(),
startDate: moment(),
endDate: moment().add(1, 'years'),
ranges: {
'Semaine prochaine': [moment(), moment().add(1, 'weeks')],
'Mois prochain': [moment(), moment().add(1, 'months')],
'3 mois prochains': [moment(), moment().add(3, 'months')],
'6 mois prochains': [moment(), moment().add(6, 'months')],
'L\'année prochaine': [moment(), moment().add(1, 'years')]
},
alwaysShowCalendars: true,
locale: {
"customRangeLabel": "Libre choix",
"format": "DD-MM-YYYY"
}
});
break;
}
daterangepicker.on('hide.daterangepicker', function (ev, picker) {
var startdate = picker.startDate.format('YYYY-MM-DD');
var enddate = picker.endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
updateURLParameters();
performSearch();
});
if (searchLocationSelect.length) {
searchLocationSelect.selectize({
create: false,
sortField: {
field: 'text',
direction: 'asc'
},
dropdownParent: 'body',
plugins: ['remove_button'],
onChange: function(value) {
setLocation(value);
var size = value.length;
if (size == 1) {
enableRadius(radiusSlider);
} else {
disableAndResetRadius(radiusSlider);
}
updateURLParameters();
performSearch();
}
});
}
noUiSlider.create(radiusSlider, {
start: [0],
step: 5,
range: {
'min': 0,
'max': 100
}
});
var radiusNodes = [
document.getElementById('radius-value')
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
radiusSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
radiusNodes[handle].innerHTML = Math.round(value);
});
radiusSlider.noUiSlider.on('set', function (value) {
setRadius(value);
updateURLParameters();
performSearch();
});
var minmax_slider_options = {
start: [0,1000],
behaviour: 'drag',
connect: true,
tooltips: [wNumb({
decimals: 0
}), wNumb({
decimals: 0
})],
range: {
'min': 0,
'max': 1000
},
step: 5
};
noUiSlider.create(minMaxSlider, minmax_slider_options);
var minMaxNodes = [
document.getElementById('minmax-lower-value'),
document.getElementById('minmax-upper-value')
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
minMaxSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
minMaxNodes[handle].innerHTML = Math.round(value);
});
minMaxSlider.noUiSlider.on('set', function (values) {
setMin(values[0]);
setMax(values[1]);
updateURLParameters();
performSearch();
});
var price_slider_options = {
start: [0,50000],
behaviour: 'drag',
connect: true,
tooltips: [wNumb({
decimals: 0
}), wNumb({
decimals: 0
})],
range: {
'min': 0,
'max': 50000
},
step: 250
};
noUiSlider.create(priceSlider, price_slider_options);
var priceNodes = [
document.getElementById('price-lower-value'), // 1000
document.getElementById('price-upper-value') // 3500
];
// Display the slider value and how far the handle moved
// from the left edge of the slider.
priceSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
var value = values[handle];
priceNodes[handle].innerHTML = '€'+Math.round(value);
});
priceSlider.noUiSlider.on('set', function (values) {
setMinPrice(values[0]);
setMaxPrice(values[1]);
updateURLParameters();
performSearch();
});
/** Reset methods **/
$('#resetLocations').on('click', function(e) {
e.preventDefault();
var locationInputField = $('.stb-search-location');
var control = locationInputField[0].selectize;
control.clear();
});
$('#resetRadius').on('click', function(e) {
e.preventDefault();
document.getElementById('radius-slider').noUiSlider.set(0);
});
$('#resetMinMax').on('click', function(e) {
e.preventDefault();
document.getElementById('min-max-slider').noUiSlider.set([0,1000]);
});
$('#resetPrice').on('click', function(e) {
e.preventDefault();
document.getElementById('price-slider').noUiSlider.set([0,50000]);
});
$('#resetInterests').on('click', function(e) {
e.preventDefault();
searchSelectedInterests = [];
$("input[name='interests[]']").iCheck('uncheck');
});
$('#resetSdgs').on('click', function(e) {
e.preventDefault();
searchSelectedSdgs = [];
$("input[name='sdgs[]']").iCheck('uncheck');
});
$('#resetDate').on('click', function(e) {
e.preventDefault();
$('#searchdaterange').data('daterangepicker').setStartDate(moment());
$('#searchdaterange').data('daterangepicker').setEndDate(moment().add(1, 'years'));
var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
performSearch();
});
$('#resetEngagement').on('click', function(e) {
e.preventDefault();
searchSelectedEngagements = [];
$("input[name='engagement[]']").iCheck('uncheck');
});
// Set initial parameters (and pre-fill the filters based on query params)
setupConfig(radiusSlider);
});
function getQueryStringValue(){
var currentURL = new URI();
var queryParams = currentURL.query(true);
if ($.isEmptyObject(queryParams) === false) {
return queryParams;
} else {
return undefined;
}
}
//In here we read the query parameters from the URL and set the filters to the query parameters (+ do initial filtering)
function setupConfig(radiusSlider) {
var queryParams = getQueryStringValue();
if (queryParams !== undefined) {
var locations = queryParams.locations;
if (locations !== undefined) {
var locationsArray = locations.split(";");
fillLocations(locationsArray);
if (locationsArray.length != 1) {
disableAndResetRadius(radiusSlider);
}
} else {
disableAndResetRadius(radiusSlider);
}
var distance = queryParams.distance;
if (distance !== undefined) {
if (locationsArray.length != 1) {
disableAndResetRadius(radiusSlider);
} else {
document.getElementById('radius-slider').noUiSlider.set(distance);
}
}
var minEmployees = queryParams.minemployees;
var maxEmployees = queryParams.maxemployees;
if ((minEmployees !== undefined) && (maxEmployees !== undefined)) {
document.getElementById('min-max-slider').noUiSlider.set([minEmployees,maxEmployees]);
}
var minPrice = queryParams.minprice;
var maxPrice = queryParams.maxprice;
if ((minPrice !== undefined) && (maxPrice !== undefined)) {
document.getElementById('price-slider').noUiSlider.set([minPrice,maxPrice]);
}
var interests = queryParams.interests;
if (interests !== undefined) {
var interestsArray = interests.split(";");
fillInterests(interestsArray);
}
var sdgs = queryParams.sdgs;
if (sdgs !== undefined) {
var sdgsArray = sdgs.split(";");
fillSdgs(sdgsArray);
}
var startdate = queryParams.startdate;
var enddate = queryParams.enddate;
if ((startdate !== undefined) && (enddate !== undefined)) {
$('#searchdaterange').data('daterangepicker').setStartDate(moment(startdate));
$('#searchdaterange').data('daterangepicker').setEndDate(moment(enddate));
var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
setStartDate(startdate);
setEndDate(enddate);
}
var engagements = queryParams.engagements;
if (engagements !== undefined) {
var engagementsArray = engagements.split(";");
fillEngagements(engagementsArray);
}
} else {
disableAndResetRadius(radiusSlider);
performSearch();
}
}
function fillLocations(locations) {
var selectize = $('.stb-search-location');
selectize[0].selectize.setValue(locations);
}
function fillInterests(interests) {
for (var i = 0; i < interests.length; i++) {
var checkboxId = "interest-"+interests[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function fillSdgs(sdgs) {
for (var i = 0; i < sdgs.length; i++) {
var checkboxId = "sdg-"+sdgs[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function fillEngagements(engagements) {
for (var i = 0; i < engagements.length; i++) {
var checkboxId = "eng-"+engagements[i];
var checkbox = $('#'+checkboxId);
checkbox.iCheck('check');
}
}
function getCurrLang() {
return $('#curr_lang').val();
}
function getCurrLangSegment() {
return $('#curr_abbr').val();
}
function getLocation() {
return $('#location').val();
}
function setLocation(value) {
searchLocation = value;
}
function setRadius(value) {
searchRadius = value;
}
function disableAndResetRadius(radiusSlider) {
radiusSlider.noUiSlider.set(0);
radiusSlider.setAttribute('disabled', true);
}
function enableRadius(radiusSlider) {
radiusSlider.removeAttribute('disabled');
}
function setMin(value) {
searchMin = value;
}
function setMax(value) {
searchMax = value;
}
function setMinPrice(value) {
searchMinPrice = value;
}
function setMaxPrice(value) {
searchMaxPrice = value;
}
function setStartDate(value) {
searchStartDate = value;
}
function setEndDate(value) {
searchEndDate = value;
}
function performSearch() {
$('#stb-items-placeholder').html('<div id="loading"><span>'+res.StbSearchPlaceholder+'</span></div>');
var searchOptions = {
type: 'POST',
url: baseUrl + '/dashboard/socialteambuildings/search/getFilteredStbs',
dataType: 'json'
};
var filterdata = {
"curr_lang" : getCurrLang(),
"curr_abbr" : getCurrLangSegment(),
"location" : getLocation(),
"interests": searchSelectedInterests,
"sdgs": searchSelectedSdgs
};
var options = $.extend({}, searchOptions, {
data: filterdata
});
// ajax done & fail
$.ajax(options).done(function (data) {
var mustacheJsonData = data.result;
var html = Mustache.render( $('#stbItemGen').html(), mustacheJsonData );
$('#stb-items-placeholder').html( html );
});
}
function updateURLParameters() {
if (searchLocation != null) {
var locationsUrlString = searchLocation.join(";");
}
var distanceUrlString = Math.round(searchRadius[0]);
var minEmployeesUrlString = Math.round(searchMin);
var maxEmployeesUrlString = Math.round(searchMax);
var minPriceUrlString = Math.round(searchMinPrice);
var maxPriceUrlString = Math.round(searchMaxPrice);
var interestUrlString = searchSelectedInterests.join(";");
var sdgUrlString = searchSelectedSdgs.join(";");
var startDateUrlString = searchStartDate;
var endDateUrlString = searchEndDate;
var engagementUrlString = searchSelectedEngagements.join(";");
var params = {locations: locationsUrlString, distance: distanceUrlString, minemployees: minEmployeesUrlString, maxemployees: maxEmployeesUrlString, minprice: minPriceUrlString, maxprice: maxPriceUrlString, interests: interestUrlString, sdgs: sdgUrlString, startdate: startDateUrlString, enddate: endDateUrlString, engagements: engagementUrlString};
var query = $.param(params);
addURLParameter(query);
}
//This function removes all the query parameters and adds the completely newly built query param string again
function addURLParameter(queryString){
var currentUrl = window.location.href;
var urlNoQueryParams = currentUrl.split("?");
var baseUrl = urlNoQueryParams[0];
var result = baseUrl + "?" + queryString;
window.history.replaceState('', '', result);
}
I tried using e.stopPropagation() and e.stopImmediatePropagation() on the remove option for example. This does not stop the events going back to the iCheck library.
Debounce will not work here as the problem is NOT in just one event listener having too many requests in a short amount of time, but with many independent event listeners firing one after the other.
Possible solutions:
Add a button eg SEARCH which will actually perform the search, instead of this being triggered by individual updates. This is a nice and simple solution to the many independent listeners problem.
If you dont want to add a new button do sth like the following. Add a timeinterval with setInterval to perform a search with AJAX. And have a flag whether a search should be performed. Then when either listener on checkbox changes simply set the flag to true. Also if a request is already in progress do NOT make another AJAX request untill the current one finishes.
pseudocode follows:
var do_search = false, timer = null, doing_ajax = false, TROTTLE = 500;
timer = setTimeout(performSearch, TROTTLE);
function performSearch()
{
if ( !do_search || doing_ajax )
{
timer = setTimeout(performSearch, TROTTLE);
return;
}
doing_ajax = true;
do_search = false;
// do the ajax request here
// ...
// NOTE: on ajax complete reset the timer, eg timer = setTimeout(performSearch, TROTTLE);
// and set doing_ajax = false;
}
// then your checkboxes listeners will simply update the do-search flag eg:
$('.searchsdgs input').on('ifChecked', function(event) {
var sdgid = event.target.value;
searchSelectedSdgs.push(sdgid);
updateURLParameters();
//performSearch();
do_search = true;
});
$('.searchsdgs input').on('ifUnchecked', function(event) {
var sdgid = event.target.value;
var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
if (arrayPos > -1) {
searchSelectedSdgs.splice(arrayPos, 1);
}
//performSearch();
do_search = true;
});
$('.searchengagements input').on('ifChecked', function(event) {
var social_engagement_id = event.target.value;
searchSelectedEngagements.push(social_engagement_id);
updateURLParameters();
//performSearch();
do_search = true;
});
$('.searchengagements input').on('ifUnchecked', function(event) {
var social_engagement_id = event.target.value;
var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
if (arrayPos > -1) {
searchSelectedEngagements.splice(arrayPos, 1);
}
//performSearch();
do_search = true;
});
NOTE you can adjust the TROTTLE interval to balance between more immediate interactivity and less AJAX requests. Experiment with different values to get a feeling for it for your app.
NOTE2 You can build on this example and make it like a multi-debounce function for example by clearing the timeout and resetting it in each individual listener (instead of simply setting do_search=true you can set do_search=true and clear the previous interval and reset it again). This will make sure only the last update will be performed.
I've defined a function to check whether a date has an event that returns true or false. For some reason, it's turning the cell of the next day to the color instead of the day that has an event. Oddly enough, my partner is using linux and it displays correctly for him, but every computer or vm i try it on with any operating system displays incorrectly. Here is the relevant code and a jsfiddle that displays the problem:
$(document).ready(function() {
var events = [];
$.ajax({
url : 'https://showmeyouraxels.me/browse.php',
type : 'post',
dataType: 'json',
success: function(e){
console.log(e[0].title);
for(var i = 0; i < e.length; i++){
events.push({
title : e[i].title,
start : moment(e[i].start).toDate('2017/07/18 12h:00'),
end : moment(e[i].end).toDate('2017/07/18 12h:30'),
icon: "https://www.qrstuff.com/images/sample.png",
});
}
console.log(events);
createCalendar();
}
});
function createCalendar(){
var calendar = $('#calendar').fullCalendar({
customButtons: {
myCustomButton: {
text: 'Add Event',
click: function() {
alert('add event');
}
}
},
header: {
left: 'prev',
center: 'title',
right: 'next'
},
editable : false,
eventLimit: true,
eventLimitText: '',
dayRender: function (date, cell) {
if ( !dateHasEvent(date) ){
cell.css("background-color", "initial");
console.log('no event ' + date.toDate());
}
else if ( dateHasEvent(date) ){
cell.css("background-color", "#6b7c8c");
console.log('event ' + date.toDate());
}
},
eventClick: function(calEvent, jsEvent, view, element) {
var inner = new Date(calEvent.start) + ' to ' + new Date(calEvent.end);
swal({
title: calEvent.title,
html: true,
text: inner,
allowOutsideClick: true
});
},
dayClick: function(dayEvent, jsEvent, view, element){
console.log(dayEvent);
},
eventRender: function(event, element) {
element.find('.fc-content').html('<img src="http://simpleicon.com/wp-content/uploads/flag.svg" height="10px"/><br>' +event.title);
},
});
calendar.fullCalendar( 'addEventSource', events);
}
function dateHasEvent(date) {
var hasEvent = false;
for(var i = 0; i < events.length; i++){
var thatDate = events[i].start.toString();
thatDate = thatDate.split(' ');
thatDate = thatDate[1] +' '+thatDate[2] +' '+thatDate[3];
var thisDate = date.toDate().toString();
thisDate = thisDate.split(' ');
thisDate = thisDate[1] +' '+thisDate[2] +' '+thisDate[3];
if(thisDate == thatDate){
hasEvent = true;
}
}
return hasEvent;
}
});
JSFiddle
I've been scratching my head for the past day and i'd have to imagine it's something stupid that i'm missing.
Thank you for any help you can provide!
Good day, i'm using fullcalendar plugin to show events on my calendar. right now i'm having a problem on displaying the events in my calendar. i am using json result to get the data that will show on my calendar..
here's my code
Controller:
[DontWrapResult]
public JsonResult GetCalendarEvents(string start, string end)
{
var fromDate = Convert.ToDateTime(start);
var toDate = Convert.ToDateTime(end);
var result = _utils.GetEventsCalendar("ALL", fromDate, toDate);
var eventList = from item in result
select new
{
id = item.CalendarId.ToString(),
title = item.Title,
description = item.Description,
start = item.FromDate.ToLocalTime().ToString("s"),
end = item.EndDate.HasValue ? item.EndDate.Value.ToLocalTime().ToString("s") : item.FromDate.ToLocalTime().ToString("s"),
NoofGuests = item.NoofGuests,
allDay = item.AllDay,
type = item.CalType,
requestedBy = item.RequestedBy,
driverName = item.DriverName,
providerName = item.ProviderName,
phoneNo = item.PhoneNo,
controlNumber = item.ControlNumber,
status =item.StatusId
};
var rows = eventList.ToArray();
return Json(rows, JsonRequestBehavior.AllowGet);
}
then in my javascript:
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
droppable: false, // this allows things to be dropped onto the calendar
events: '#Url.Action("GetCalendarEvents/")',
eventRender: function (event, element) {
element.attr('href', 'javascript:void(0);');
if (event.start <date && event.end <date) {
element.css('background-color', '#ed5565');
element.css('border', '1px solid #ed5565');
} else if (event.start <=date && event.end >= date) {
element.css('background-color', '#f8ac59');
element.css('border', '1px solid #f8ac59');
}
if (event.status == 1) {
element.css('background-color', '#0000FF');
element.css('border', '1px solid #0000FF');
} else if (event.status == 4)
{
element.css('background-color', '#00CC33');
element.css('border', '1px solid #00CC33');
}
element.click(function () {
if (event.type == 'Event') {
$('#forBook').hide();
$('#permitdetails').hide();
$('#delPer').show();
var url = '#Url.Action("Edit", "Events")?id=' + event.id;
}
else if (event.type == 'ApproveBook') {
$('#forBook').show();
$('#permitdetails').hide();
$('#delPer').show();
$("#NoofGuests").html(event.NoofGuests);
}
else {
$('#forBook').hide();
$('#permitdetails').hide();
$('#delPer').show();
var url = '#Url.Action("Edit", "Announcements")?id=' + event.id;
}
if (event.type == 'DeliveryPermit') {
$('#delPer').hide();
$('#permitdetails').show();
$("#controlNo").html(event.controlNumber);
$("#requestby").html(event.requestedBy);
$("#deliverydate").html(moment(event.start).format('MMM Do'));
$("#contractor").html(event.providerName);
$("#contact").html(event.phoneNo);
$("#drivername").html(event.driverName);
if (event.status == 1) { $("#status").html("Arrived"); }
else if (event.status == 4) { $("#status").html("Completed"); }
else { $("#status").html("Submitted"); }
//getDetails(event.id);
var urls = '#Url.Action("Calendarpermit", "AdminHome")?id=' + event.id + '&strHide=' + "strHide";
var url = '#Url.Action("Edit", "DeliveryPermits",new { area = "Permit" })/' + event.id
$.ajax({
url: urls,
cache: false,
data: {id : event.id},
contentType: 'application/html; charset=utf-8',
type: "POST",
dataType: "html",
success: function (data){
$('#permitItem').html(data);
}
});
}
if (event.type == 'Announcement') {
$('#forBook').hide();
$('#permitdetails').hide();
$('#delPer').show();
$("#startTime").html(moment(event.start).format('MMM Do '));
$("#endTime").html(moment(event.start).format('MMM Do'));
} else {
$("#startTime").html(moment(event.start).format('MMM Do h:mm A'));
$("#endTime").html(moment(event.end).format('MMM Do h:mm A'));
}
$("#eventInfo").html(event.description);
$("#eventLink").attr('href', url);
$("#eventContent").dialog({
modal: true, title: event.title, width: 350
});
});
}
});
i tried to put an alert inside the eventRender but it didn't pass or show data in my calendar.. what i am doing wrong? thanks in advance
I am using AJAX to get the data and make them into an array like below:
function drawDate(username, date, device, token){
$.ajax({
type: 'GET',
url: dsu + "dataPoints/" + getDatapointId(username, date, device),
headers: {
"Authorization": "Bearer " + token
},
success : function(data, device) {
var location_events = []; //***** Here is the array variable.
if(device == "android" || device == "ios") {
rows = data["body"]["episodes"].map(function (epi) {
var state = epi["inferred-state"].toLocaleUpperCase();
var start = new Date(epi["start"]);
var end = new Date(epi["end"]);
var long_lat = epi["location-samples"];
if (state == "STILL") {
var longitude_sum = 0;
var latitude_sum = 0;
long_lat.forEach(function(obj) {
longitude_sum += obj['longitude'];
latitude_sum += obj['latitude'];
});
return [state, start, end, latitude_sum / long_lat.length, longitude_sum / long_lat.length];
}
});
//**** I pushed the data into the array.
rows.forEach(function(obj){
if (typeof obj !== 'undefined') {
location_events.push({
title: 'location',
start: moment(obj[1]).format().substring(0, 19),
end: moment(obj[2]).format().substring(0, 19),
url: "https://maps.googleapis.com/maps/api/staticmap?center="+ obj[3] + "," + obj[4] + "&zoom=15&size=2000x1000&maptype=roadmap&markers=color:red%7Clabel:S%7C" + obj[3] + "," + obj[4] + "&markers=size:mid"
})
}
});
console.log(location_events);
return location_events
}
},
error: function(data){
console.log('Data did not have any locations.')
}
});
}
Then when I tried to call that function, it returned "undefined". I actually want to put that array into FullCalendar like below:
$(document).ready(function() {
var today = moment();
var token = url("#access_token");
$.getJSON(dsu + "oauth/check_token?token=" + token)
.done(function(data) {
var username = data["user_name"];
var device = 'android';
var date = url("#date")? moment(url("#date")).toDate() : new Date();
var redraw = function(){
var test = drawDate(username, moment(date).format('YYYY-MM-DD'), device, token);
console.log(test); //***** Here! I tried to make the return of the function into a variable but it returned "undefined"
};
$('#calendar').fullCalendar({
header: '',
defaultDate: '2015-08-03',
defaultView: 'agendaDay',
allDaySlot: false,
slotEventOverlap: false,
events: test, //******* I want to the array to be rendered here.
eventAfterRender: function(event, element, view) {
$(element).attr("id", "event_id_" + event.id);
}
});
})
.fail(function() {
console.log("Fail!");
});
I read most of the similar questions and it seems that I should use callback function but I don't really understand how to use them.
Thank you very much! Any help is welcome!
The problem is that you do AJAX request which is asynchronous and you cannot return this data from drawDate() function. You need to do what you need with data retrieved from server in your 'success' callback. Like following:
success : function(data, device) {
var location_events = []; //***** Here is the array variable.
if(device == "android" || device == "ios") {
rows = data["body"]["episodes"].map(function (epi) {
var state = epi["inferred-state"].toLocaleUpperCase();
var start = new Date(epi["start"]);
var end = new Date(epi["end"]);
var long_lat = epi["location-samples"];
if (state == "STILL") {
var longitude_sum = 0;
var latitude_sum = 0;
long_lat.forEach(function(obj) {
longitude_sum += obj['longitude'];
latitude_sum += obj['latitude'];
});
location_events = [state, start, end, latitude_sum / long_lat.length, longitude_sum / long_lat.length];
}
});
//**** I pushed the data into the array.
rows.forEach(function(obj){
if (typeof obj !== 'undefined') {
location_events.push({
title: 'location',
start: moment(obj[1]).format().substring(0, 19),
end: moment(obj[2]).format().substring(0, 19),
url: "https://maps.googleapis.com/maps/api/staticmap?center="+ obj[3] + "," + obj[4] + "&zoom=15&size=2000x1000&maptype=roadmap&markers=color:red%7Clabel:S%7C" + obj[3] + "," + obj[4] + "&markers=size:mid"
})
}
});
console.log(location_events);
}
$('#calendar').fullCalendar({
header: '',
defaultDate: '2015-08-03',
defaultView: 'agendaDay',
allDaySlot: false,
slotEventOverlap: false,
events: location_events,
eventAfterRender: function(event, element, view) {
$(element).attr("id", "event_id_" + event.id);
}
});
}