I included a calendar in my project using fullcalendar.js. My database entries are showing up but they are one month ahead.
If I enter something for 16.octobre.2015, it will be saved in the database as 16.octobre.2015 but will be displayed as 16.novembre.2015. This happens with every single one of my entries.
I searched a lot here on Stack Overflow and found a few similar topics. In one, someone explained that this has something to do with how months are indexed.
PHP counts from 1 to 12.
JavaScript counts from 0 to 11.
I guess that maybe this is my problem?
Can someone tell me what I need to change, so that my entries show correctly? Here is my code:
<!-- inline scripts related to this page -->
<script type="text/javascript">
jQuery(function($) {
/* initialize the external events
-----------------------------------------------------------------*/
$('#external-events div.external-event').each(function() {
// create an Event Object (http://arshaw.com/fullcalendar/docs/event_data/Event_Object/)
// it doesn't need to have a start or end
var eventObject = {
title: $.trim($(this).text()) // use the element's text as the event title
};
// store the Event Object in the DOM element so we can get to it later
$(this).data('eventObject', eventObject);
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
/* initialize the calendar
-----------------------------------------------------------------*/
<?php
print "var date = new Date();\n";
print "var d = date.getDate();\n";
print "var m = date.getMonth();\n";
print "var y = date.getFullYear();\n";
print "var unixTimestamp = Date.now(); // in milliseconds;"
?>
var calendar = $('#calendar').fullCalendar({
//isRTL: true,
buttonHtml: {
prev: '<i class="ace-icon fa fa-chevron-left"></i>',
next: '<i class="ace-icon fa fa-chevron-right"></i>'
},
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
<?php
$dates=getPcalInfoOfHour($gl_userid,0,0);
print "events: [\n";
for ($x=0;$x<count($dates["id"]);$x++) {
print " {\n";
print " title: '".$dates["title"][$x]."',\n";
print " start: new Date(".date("Y",$dates["start"][$x]).", ".date("n",$dates["start"][$x]).", ".date("j",$dates["start"][$x]).", ".date("G",$dates["start"][$x]).", ".date("i",$dates["start"][$x]).",0,0),\n";
print " end: new Date(".date("Y",$dates["end"][$x]+1).", ".date("n",$dates["end"][$x]+1).", ".date("j",$dates["end"][$x]+1).", ".date("G",$dates["end"][$x]+1).", ".date("i",($dates["end"][$x]+1)).",0,0),\n";
print " allDay: false,\n";
print " className: 'label-info'\n";
if ($x<(count($dates["id"])-1)) {
print " },\n";
} else {
print " }\n";
}
}
print "]\n";
?>
,
editable: true,
droppable: true, // this allows things to be dropped onto the calendar !!!
drop: function(date, allDay) { // this function is called when something is dropped
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
var $extraEventClass = $(this).attr('data-class');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
copiedEventObject.allDay = allDay;
if($extraEventClass) copiedEventObject['className'] = [$extraEventClass];
// render the event on the calendar
// the last `true` argument determines if the event "sticks" (http://arshaw.com/fullcalendar/docs/event_rendering/renderEvent/)
$('#calendar').fullCalendar('renderEvent', copiedEventObject, true);
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
}
,
selectable: true,
selectHelper: true,
select: function(start, end, allDay) {
calendar.fullCalendar('unselect');
}
,
eventClick: function(calEvent, jsEvent, view) {
//display a modal
var modal =
'<div class="modal fade">\
<div class="modal-dialog">\
<div class="modal-content">\
<div class="modal-body">\
<button type="button" class="close" data-dismiss="modal" style="margin-top:-10px;">×</button>\
<form class="no-margin">\
<label>Title </label>\
<label>$dates["title"][0]</label>\
<button type="submit" class="btn btn-sm btn-success"><i class="ace-icon fa fa-check"></i> Save</button>\
</form>\
</div>\
<div class="modal-footer">\
<button type="button" class="btn btn-sm btn-danger" data-action="delete"><i class="ace-icon fa fa-trash-o"></i> Delete Event</button>\
<button type="button" class="btn btn-sm" data-dismiss="modal"><i class="ace-icon fa fa-times"></i> Cancel</button>\
</div>\
</div>\
</div>\
</div>';
var modal = $(modal).appendTo('body');
modal.find('form').on('submit', function(ev){
ev.preventDefault();
calEvent.title = $(this).find("input[type=text]").val();
calendar.fullCalendar('updateEvent', calEvent);
modal.modal("hide");
});
modal.find('button[data-action=delete]').on('click', function() {
calendar.fullCalendar('removeEvents' , function(ev){
return (ev._id == calEvent._id);
})
modal.modal("hide");
});
modal.modal('show').on('hidden', function(){
modal.remove();
});
console.log(calEvent.id);
console.log(jsEvent);
console.log(view);
// change the border color just for fun
//$(this).css('border-color', 'red');
}
});
})
</script>
The answer is literally in the question. I'll just quote you:
I searched a lot here on Stack Overflow and found a few similar topics. In one, someone explained that this has something to do with how months are indexed.
PHP counts from 1 to 12.
JavaScript counts from 0 to 11.
I guess that maybe this is my problem?
Yes. If you need a finger pointed in the right direction, let's take this part of your code:
print " start: new Date(".date("Y",$dates["start"][$x]).", ".date("n",$dates["start"][$x]).", ".date("j",$dates["start"][$x]).", ".date("G",$dates["start"][$x]).", ".date("i",$dates["start"][$x]).",0,0),\n";
print " end: new Date(".date("Y",$dates["end"][$x]+1).", ".date("n",$dates["end"][$x]+1).", ".date("j",$dates["end"][$x]+1).", ".date("G",$dates["end"][$x]+1).", ".date("i",($dates["end"][$x]+1)).",0,0),\n";
More precisely this:
date("n", $dates["start"][$x])
date("n", $dates["end"][$x]+1)
Simply subtract one from the month value:
(date("n", $dates["start"][$x]) - 1)
(date("n", $dates["end"][$x]+1) - 1)
Do this everytime you output a PHP month value in a JavaScript source.
Even better, you could just use the timestamps directly (remember that JavaScript uses milliseconds):
print " start: new Date(".($dates["start"][$x] * 1000)."),\n";
print " end: new Date(".(($dates["end"][$x]+1) * 1000)."),\n";
Related
Unsing clipboard, I try to copy a html text, but the copy is correct without the html code.
I have 2 button, one for the plain text, one for the html code (copy image link)
Do you have any idea where is the problem ?
Html code
<div id="Area-output" class="text-bg-light"></div>
<button id="copyResultButton" class="btn btn-primary d-none" data-clipboard-target="#Area-output">
<i class="bi bi-clipboard" title="Copy Result"></i> Copy Result
</button>
<button id="copyHTMLButton" class="btn btn-primary d-none" data-clipboard-target="#Area-output" data-clipboard-action="copy">
<i class="bi bi-code" title="Copy HTML"></i> Copy HTML
</button>
Now the javascript code
$(document).ready(function() {
// Initialize the clipboard for result button
var clipboardResult = new ClipboardJS("#copyResultButton");
// Handler for when the result button is clicked
clipboardResult.on("success", function(e) {
// Show a tooltip indicating that the text was copied
$(e.trigger).tooltip({title: "Copied!", placement: "bottom", trigger: "manual"}).tooltip("show");
setTimeout(function() {
$(e.trigger).tooltip("hide");
}, 1000);
e.clearSelection();
});
// Initialize the clipboard for HTML button
var clipboardHTML = new ClipboardJS("#copyHTMLButton", {
text: function() {
return $("#Area-output").html();
}
});
// Handler for when the HTML button is clicked
clipboardHTML.on("success", function(e) {
// Show a tooltip indicating that the HTML was copied
$(e.trigger).tooltip({title: "Copied HTML!", placement: "bottom", trigger: "manual"}).tooltip("show");
setTimeout(function() {
$(e.trigger).tooltip("hide");
}, 1000);
e.clearSelection();
});
$("#send").click(function() {
let message = $("#message").val();
let engine = $("#engine").val();
let save = $("#save").val();
$.post("' . $url . '", {message: message, engine: engine, save: save}, function(data) {
$("#Area-output").html(data);
// Show the copy buttons after the chat message is generated
$("#copyResultButton, #copyHTMLButton").removeClass("d-none");
});
});
});
I work with fullcalendar 3 with laravel.
The draggable events are courses and should be different every week. I want to dynamically change the courses when I change the week in the calendar.
At the moment in the controller I have a function that give me every course:
public function index()
{
$corsi = Corso::select('titolo', 'descrizione','ore_45esimi')->get();
return view('lezione.calendario_lezioni')->with(array('corsi' => $corsi));
}
then in the view I display the events using a div:
<div id="external-events">
#foreach($corsi as $corso)
<div class="external-event bg-formazione">{{$corso->titolo }}
<br>
<div style="font-size: small">{{$corso->descrizione }} </div>
<input id="ore" type="hidden" value="{{$corso->ore_45esimi }}">
</div>
#endforeach
</div>
And in the Fullcalendar js file I have a function to make the courses draggable:
function ini_events(ele) {
ele.each(function () {
let eventObject = {
title: $(this).contents()
.filter(function () {
return !!$.trim(this.innerHTML || this.data);
})
.first().text(),
descrizione: $.trim($(this).contents()[3].firstChild.textContent),
ore: $(this).contents('#ore').val(),
color: $(this).css("background-color"),
};
$(this).data('event', eventObject);
$(this).draggable({
zIndex: 1070,
revert: true,
revertDuration: 0
});
});
}
ini_events($('#external-events div.external-event'));
I found the viewRender function that allow me to get the begin and the end of the displayed week:
$('#calendar').fullCalendar({
...
viewRender: function (element) {
var start = moment(element.intervalStart).format();
var end = moment(element.intervalEnd).subtract(1, 'd').format();
},
});
How can I use the start and end variable into the index method in the controller's query when I first show the calendar and every time I change the week?
You wish to pass two javascripts variables in php. There is huge literature on this issue, see for example
Laravel blade pass Javascript variable in php
There are many possible solutions.
I prefer pass the values of the variables through an url to a new method and after through session to the index method.
1) routes/web.php
Route::get('yourproject/{start}/{end}/getstartandend','yourController#getstartandend');
2) view
$('#calendar').fullCalendar({
...
viewRender: function (element) {
var start = moment(element.intervalStart).format();
var end = moment(element.intervalEnd).subtract(1, 'd').format();
},
});
...
appBase="{!!URL::to('/')!!}";
var route = appBase + "/yourproject/"+start+"/"+end+"/getstartandend";
$.get(route);
3) yourController
public function index ()
{
$corsi = Corso::select('titolo', 'descrizione','ore_45esimi')->get();
return view('lezione.calendario_lezioni')->with(array('corsi' => $corsi));
$start = session('start');
$end = session('end');
....
}
public function getstartandend ($start, $end)
{
session(['start' => $start]);
session(['end' => $end]);
}
I'm working on a FullCalendar; there are 9-10 events everyday in it and now I have to create the ability to delete an event.
This is the code:
eventClick: function(event, jsEvent, view) {
$('#modalTitle').html(event.title);
var imgName=event.image;
document.getElementById('imageDiv').innerHTML = '<img src='+imgName+' onerror=".'this.style.display="none"'." class=".'img-responsive'." alt=".''." >';
$('#modalBody').html(event.description);
$('#eventid').html(event.id);
$('#startTime').html(moment(event.start).format('DD-MM-YYYY'));
$('#endTime').html(moment(event.end).format('DD-MM-YYYY'));
$('#eventUrl').attr('href',event.url);
$('#fullCalModal').modal();
return false;
}
I get the events list with this:
echo events: [
";
while ($row = mysqli_fetch_array($sql)) {
echo "
{
id: '".$row['id']."',
title: '".$row['title']."',
image: 'assets/uploads/".$row['image']."',
description: '<p>".$row['description']."</p>',
start: '".$row['start']."',
end: '".$row['end']."',
url: '".$row['url']."',
color: '".$row['color']."',
allDay: true
},";
} ;
echo "
]
And now, when a user clicks on an event, the modal should popup with additional details and a button for deleting the event.
This is handled with:
function modalEvents(){
echo "
<div id='fullCalModal' class='modal fade'>
...
<p id='eventid'></p>
</div>
</div>
</div>
<div class='modal-footer'>
<a href='javascript:EliminateEvent(\"event.id\")' class='btn btn-danger btn-sm' role='button'><i class='fa fa-fw fa-trash'></i>Brisanje rezervacije</a>
However... the problem is that I get the actual ID value in , however, I'm having a hard time getting the same result in the link, the javascript:EliminateEvent()
Is there a way that I could get as a result
<a href='javascript:EliminateEvent(123)>
instead of
<a href='javascript:EliminateEvent(event.id)>
The reason you are getting the string "event.Id" in the function parameter is because you are actually asking PHP to do that. When you click on the event you could set the event id with JavaScript like you did with all the details. Like: href="javascript:EliminateEvent(" + event.id + ")"
Supposing that I want to open a modal popup when user clicks on a FullCalendar's event, I wrote some logic on the "eventClick" part of Full Calendar. This works fine until I'm on the default view, which I setted as "month".
If I try to switch from a view to another, though, this doesn't get fired, almost like it died.
What am I doing wrong? This is the code that I have for my Full Calendar. I've also tried to add a viewRender event as per the documentation but it's not working
function initCalendar2(oggetti){
debugger;
$('.calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
//right: 'month,agendaWeek,agendaDay,' +vistaAgenda
right: 'month,agendaWeek,agendaDay,listDay,listWeek'
},
views: {
listDay: { buttonText: 'Lista Giorno'},
listWeek: { buttonText: 'Lista Sett'}
},
eventClick: function(calEvent, jsEvent, view) {
debugger;
//Send 2 values to the modal
$("#dataArrivo").val(calEvent.start.toISOString().split('T')[0]);
$("#dataConsegna").val(calEvent.end.toISOString().split('T')[0]);
//Opens the modal
var targeted_popup_class = $(this).attr('data-popup-open');
$('[data-popup="' + targeted_popup_class + '"]').fadeIn(350);
//e.preventDefault();
var newDateOne;
var newDateTwo;
//This triggers only when the save button of the modal is clicked
setTimeout(function() {
$("#save").click(function() {
var tmp1 = $("#dataArrivo").val();
var tmp2 = $("#dataConsegna").val();
newDateOne = new Date(tmp1);
newDateOne.setDate(newDateOne.getDate());
newDateTwo = new Date(tmp2);
newDateTwo.setDate(newDateTwo.getDate());
var tmp = calEvent.id.split("&");
var idToSend = "";
for (var i = 0; i < tmp.length-1; i++) {
if (i == tmp.length-2) {
idToSend += tmp[i];
} else {
idToSend += tmp[i]+"&";
}
} if (newDateOne !== calEvent.start || newDateTwo !== calEvent.end) {
var actualDate = new Date(calEvent.start);
debugger;
//This ajax call will save the event's new dates in the DB
$.ajax({
url: 'calendariomanagement/listaPraticheFormJSONByIdProgettoCommittenteAndTipoVal/'+ idToSend +'/modDate/' + nuovaDataArrivo.toDateString() + '&' + nuovaDataConsegna.toDateString() + '&' + actualDate.toDateString(),
type:'POST',
async:false,
success: function(data) {
var targeted_popup_class = $(this).attr('data-popup-close');
$('[data-popup="' + targeted_popup_class + '"]').fadeOut(350);
location.reload();
/*calEvent.start = dataUno;
calEvent.end = dataDue;
$('#calendar').fullCalendar('updateEvent', calEvent);*/
}
});
}
}), 350}
);
},
viewRender: function(view, element) {
debugger;
$('#calendar').fullCalendar('rerenderEvents');
},
locale: 'it',
defaultView: 'month',
defaultDate: moment(),
navLinks: true, // can click day/week names to navigate views
editable: false,
eventDurationEditable: false,
//weekends:false,
eventLimit: true, // allow "more" link when too many events
events: oggetti
});
Putting here for anybody that might fall in something similar my problem.
This was the modal popup that I was defining with HTML
<!-- Modal -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog">
*<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Cambio data</h4>
</div>
<div class="modal-body">
<p> Inserire i nuovi valori nel formato anno-mese-giorno (es.: 2018-07-03). Nel
caso non si volesse modificare nessun campo, semplicemente chiudere questo pop-up</p>
<label for="arrivo">Data Arrivo:</label>
<input type="text" name="dataArrivo" id="dataArrivo" class="form-control">
<label for="consegna">Data Riconsegna:</label>
<input type="text" name="dataConsegna" id="dataConsegna" class="form-control">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Chiudi</button>
<button type="button" class="btn btn-default" id="save" data-dismiss="modal">Salva</button>
</div>
</div>
*
After FullCalendar's load, I added this with jQuery
$(".fc-content").attr('data-toggle', 'modal');
$(".fc-content").attr('data-target','#myModal');
But of course, after changing the view, those attributes were lost and there was no chance to reinsert them. As a solution (pointed out by ADyson), the workaround was to define a modal with a bootbox object so that I could have it dynamically
I have an array joined with commas in a tooltip. However I want each one be on it's own line. I've tried a few things but none seem to be working. The code is a knockout observable to which I am new too.
Here is my ko observable:
this.campaignTagString = ko.observable("");
(function() {
if(data.campaignTags != undefined) {
var array = [];
for(var tag in data.campaignTags){
array.push(data.campaignTags[tag].name);
}
//Join our campaign tag name array
var tagString = array.join(", " + '<br />');
$('#tooltip-campaigntags').tooltip({
content: function(callback) {
callback($(this).prop('title').replace('|', '<br />'));
}
});
var textCampaign = "Campaigns: ";
o.campaignTagString(textCampaign + tagString);
}
})();
I am calling it like so:
<span id="tooltip-campaigntags" class="label label-default label-mini" data-bind="html: '<i class=\'fa fa-tags\'></i> '+campaignTags().length, tooltip: { title: campaignTagString , placement: 'bottom' }" data-toggle="tooltip" data-placement="bottom" title="" >
</span>
Any help would be great, thanks!
Some tips:
You have an error in your code: if campaignTags is an object, campaignTags().length will not work; if it is an array, data.campaignTags[tag].name will not work.
You might find it useful to have a look at Knockout-Bootstrap, a Bootstrap adaptation that provides Knockout bindingHandlers for Bootstrap JS functions (used in demo below).
The Bootstrap documentation mentions the option {html: true} if you want your content not to be encoded into text.
Additionally, your IIFE (the function in which you wrapped the bootstrap tooltip functionality) should rather be a computed observable on your view model, as well as the icon html, and the string, all depending on campaignTags.
Below are the resulting JS viewModel and HTML binding if you follow these tips:
//params === object containing tag objects like -- tagX: {name: 'tag'}
function VM(params) {
var self = this;
this.campaignTags = params;
this.campaignTagsArray = ko.computed(function() {
var array = [];
for(var tag in self.campaignTags) {
array.push(self.campaignTags[tag].name);}
return array;});
this.campaignTagString = ko.computed(function() {
return "Campaigns: <br>" +
self.campaignTagsArray().join(", " + '<br />'); });
this.html = ko.computed(function() {
return '<i class="fa fa-tags"></i> ' +
self.campaignTagsArray().length });
}
And the HTML binding:
<span class="label label-default label-mini" data-bind="
html: html(),
tooltip: { html: true, title: campaignTagString() , placement: 'bottom'}">
</span>
Check out the fiddle for a demo.