I am using adesigns/calendar-bundle. The calendar is already showing. However, when I click on any given date, it does not let me add an event. Moreover, I have create an entity class that is persisted to the database to store events. I load them and when I want to display them, it throws me an error: http://localhost/guilford/web/app_dev.php/fc-load-events Failed to load resource: the server responded with a status of 500 (Internal Server Error)
CalendarListener.php
<?php
namespace AppBundle\EventListener;
use ADesigns\CalendarBundle\Event\CalendarEvent;
use ADesigns\CalendarBundle\Entity\EventEntity;
use Doctrine\ORM\EntityManager;
class CalendarEventListener
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function loadEvents(CalendarEvent $calendarEvent)
{
$request = $calendarEvent->getRequest();
$filter = $request->get('filter');
$em = $this->getDoctrine()->getManager();
$events =$em->getRepository('AppBundle:CalendarEvent')
->findAll();
foreach ($events as $event) {
// create an event with a start/end time, or an all day event
if ($event->getAllDay() === false) {
$eventEntity = new EventEntity($event->getTitle(), $event->getStartDate(), $event->getEndDate());
} else {
$eventEntity = new EventEntity($event->getTitle(), $event->getStartDate(), null, true);
}
$calendarEvent->addEvent($eventEntity);
}
}
}
Calendar-settings.js
$(function () {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#calendar-holder').fullCalendar({
header: {
left: 'prev, next',
center: 'title',
right: 'month, basicWeek, basicDay,'
},
lazyFetching: true,
timeFormat: {
// for agendaWeek and agendaDay
agenda: 'h:mmt', // 5:00 - 6:30
// for all other views
'': 'h:mmt' // 7p
},
eventSources: [
{
url: Routing.generate('fullcalendar_loader'),
type: 'POST',
// A way to add custom filters to your event listeners
data: {
},
error: function() {
alert('There was an error while fetching Google Calendar!');
}
}
]
});
});
Related
I'm trying to use FullCalendar.io with tattali/calendar-bundle.
I want to display a calendar for a lending objects service.
So the calendar must show the days during which one object is unavialable.
The problem is I can't manage to send the object to fullcalendar so I can get the reservations and the days the object is reserved.
Here is my code for the Javascript :
document.addEventListener("DOMContentLoaded", () => {
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: [interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin],
headerToolbar: {
left: "prev,next",
center: "title",
right: "dayGridMonth,listWeek",
},
buttonText: {
today: "Today",
month: "month",
week: "week",
day: "day",
list: "list",
},
displayEventTime: false,
initialDate: Date.now(),
locale: "fr",
firstDay: "1",
// editable: true,
// dayMaxEvents: true,
eventSources: [
{
url: "/fc-load-events",
method: "POST",
extraParams: {
filters: JSON.stringify({}),
},
failure: () => {
console.log("There was an error while fetching FullCalendar!");
},
},
{
url: "/json-feed",
method: "POST",
extraParams: {
filters: JSON.stringify({}),
},
failure: () => {
console.log("There was an error while fetching FullCalendar!");
},
}
],
events: [
{
groupId: "association ouverte", // recurrent events in this group move together
daysOfWeek: ["3", "6"],
display: "background",
color: "#5c995e",
},
],
timeZone: "UTC",
});
calendar.render();
});
The Symfony controller :
// controller for displaying the page :
#[Route('/object-details/{slug}', name: 'object-details', methods: ['GET', 'POST'])]
public function detailsObject(
Object $object,
LoanRepository $loan,
): Response {
return $this->render('home/details-object.html.twig', [
'controller_name' => 'HomeController',
'object' => $object,
'loan' => $loan,
]);
}
// controller for getting json :
#[Route('/json-feed', name: 'json-feed')]
public function getJson(Request $request): JsonResponse
{
$response = new JsonResponse(['objet' => 12]);
dump($response);
return $response;
}
The json-feed route works but I don't know how to send the object details with it.
Thanks for any help.
Well I managed to do it that was pretty easy !
I was trying to send the object's data as a json but I just needed to get it with some jquery on the dom.
I did this :
//...
document.addEventListener("DOMContentLoaded", () => {
var calendarEl = document.getElementById("calendar");
// I get the object id from the dom :
var object = $("#objet-calendar").find('p').text();
//...
then I added it to the filters :
//...
{
url: "/fc-load-events",
method: "POST",
extraParams: {
filters: JSON.stringify({'object' : object}),
},
failure: () => {
console.log("There was an error while fetching FullCalendar!");
},
},
//...
Finally in onCalendarSetData()
//...
public function onCalendarSetData(CalendarEvent $calendar, $router)
{
$start = $calendar->getStart();
$end = $calendar->getEnd();
$filters = $calendar->getFilters();
$object = $this->objectRepo->findOneById($filters);
$object_id = $objet->getId();
//...
And it works
public class Home
{
string CustEmail { get;set;}
string CustName { get; set;}
int id { get; set;}
}
Model
[HttpPost]
public void CreateCustomer(Home cust)
{
if (ModelState.IsValid)
{
}
}
Controller
angular.module('myFormApp', []).controller('CustomerController', function ($scope, $http, $location, $window) {
debugger;
$scope.cust = {};
$scope.message = '';
$scope.result = "color-default";
$scope.isViewLoading = false;
//get called when user submits the form
$scope.submitForm = function () {
$scope.isViewLoading = true;
console.log('Form is submitted with:', $scope.cust);
//$http service that send or receive data from the remote server
var cust = {
CustEmail: $scope.cust.CustEmail,
CustName: $scope.cust.CustName,
id: 1,
};
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
}).then(function (data, status, headers, config) {
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
})
$scope.isViewLoading = false;
}
}).config(function ($locationProvider) {
//default = 'false'
$locationProvider.html5Mode(true);
});
I get the data in the proper format in front-end and the post-back call is also working but I cannot get value in MVC controller. I don't know what am I doing wrong. I have tried using the individual item in controller then it's working fine but i want it through model only.
The .then method of a promise only exposes one value, not four values.
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
̶}̶)̶.̶t̶h̶e̶n̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).then(function (response) {
var data = response.data;
var status = response.status;
var headers = response.headers;
var config = response.config;
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
})
For more information, see
AngularJS $http Service API Reference - returns
UPDATE
You can add a .catch block to console log any errors:
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
̶}̶)̶.̶t̶h̶e̶n̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).then(function (response) {
var data = response.data;
var status = response.status;
var headers = response.headers;
var config = response.config;
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
console.log("OK:", response.data);
}).catch(function(response) {
console.log("ERROR:", response);
});
I have a search page , once user clicks Search button it calls an angualrjs function, where I need to update some $scope variables and redirect to another page.
This is my service to share the object between controllers
var app = angular.module('MyApp', ['angular.filter', 'googlechart']);
app.factory('sharedService', function () {
var testObj = {
name:'User Name 1',
age: 25
};
var searchParameter = function (newObj) {
testObj = newObj;
};
var getParameter = function () {
return testObj;
};
return {
searchParameter: searchParameter,
getParameter: getParameter
};
});
Here is the Controller 1 : SearchController
app.controller('SearchController', function ($scope, $parse, $filter, $location, $window, sharedService) {
$scope.searchParameter = function (searchParameter) {
var testObj = {
name: 'UserName 2',
age: 35
};
sharedService.searchParameter(testObj);
$window.location.href = 'http://localhost:8080/UI/SearchResult.aspx';
}
});
And this is my controller 2 : ResultController
app.controller('ResultController', function ($scope, $parse, $filter, sharedService) {
$scope.getParameter = function () {
$scope.testParam = sharedService.getParameter();
}
});
testObj is a model.
It is redirecting to the result page, but the testObj value is not getting updated to UserName 2.
How can I get updated value in the controller 2?
This is not working because in your service, the object is declared as var. So even if you're updating from outside, it will not return the value.
Also apart from service, if your pages are like parent-child controller, you can share objects between controller. Let me know if service solution is not working, I can share solution for sharing objects between controllers.
The variable should be bound to the service. Something like below:
var app = angular.module('MyApp', ['angular.filter', 'googlechart']);
app.factory('sharedService', function () {
this.testObj = {
name:'User Name 1',
age: 25
};
var searchParameter = function (newObj) {
this.testObj = newObj;
};
var getParameter = function () {
return this.testObj;
};
return {
searchParameter: searchParameter,
getParameter: getParameter
};
});
I have a FullCalendar that takes in an array(selectedEvents) from a function that uses the Location ID that is pulled from the url. The array is built onInit as is the calendar but the calendar has a timeout on it in order to allow the events to populate. When the calendar is initially navigated to from another part of the website, the events for the Default Location are not displayed but they are populated into the selectedEvents array. When I click on another location's calendar, the events are populated and then displayed correctly. The calendar works correctly thereforth. I believe the calendar is taking precedence over the population of events during the first initialization of the calendar even though it is wrapped in a timeout. I've seen this question once before on SO but it was not answered.
I've already tried extending the timeout of the calendar
getLocationEvents(location: PFLocation) {
// if (this.allEvents) {
this.selectedEvents = [];
if (location.events) {
console.log(location.events);
this.eventIdArray = location.events;
for (let event of this.eventIdArray) {
this.eventService.get(event).subscribe(data => {
console.log(data);
this.selectedEvents.push(data);
});
}
} else {
return;
}
console.log(this.selectedEvents);
return this.selectedEvents;
}
getBatchEvents(location: PFLocation) {
var that = this;
if (this.allEvents) {
if (location.batches) {
let batches = location.batches;
for (let batch of batches) {
this.batchService.get(batch).subscribe(data => {
for (let event of data.events) {
this.eventService
.get(event)
.subscribe(eventData => {
console.log(eventData);
this.selectedEvents.push(eventData);
});
}
});
}
console.log(this.selectedEvents);
console.log('out of Batch Events');
return this.selectedEvents;
}
}
if (!this.allEvents) {
this.selectedEvents = [];
if (location.batches) {
let batches = location.batches;
for (let batch of batches) {
this.batchService.get(batch).subscribe(data => {
for (let event of data.events) {
this.eventService
.get(event)
.subscribe(eventData => {
console.log(eventData);
this.selectedEvents.push(eventData);
});
}
});
}
console.log(this.batchEvents);
console.log('out of Batch Events');
return this.selectedEvents;
}
}
}
getAllEvents(location: PFLocation) {
this.allEvents = true;
var that = this;
that.getLocationEvents(location);
that.getBatchEvents(location);
}
ngOnInit() {
let that = this;
this.sub = this.route.params.subscribe(params => {
this.locationId = params['locationid'];
this.userService
.getLocation(this.locationId)
.subscribe(location => {
console.log('Out of on Init');
this.selectedLocation = JSON.parse(
JSON.stringify(location)
);
that.getAllEvents(this.selectedLocation);
console.log(this.selectedLocation);
});`enter code here`
console.log(this.selectedLocation);
if (this.locationId) {
const today = new Date();
const y = today.getFullYear();
const m = today.getMonth();
const d = today.getDate();
$('#fullCalendar').fullCalendar('removeEvents');
$('#fullCalendar').fullCalendar(
'addEventSource',
that.selectedEvents
);
setTimeout(function() {
$('#fullCalendar').fullCalendar({
viewRender: function(view: any, element: any){
// We make sure that we activate the
perfect scrollbar when the view isn't on Month
if (view.name != 'month') {
var elem = $(element).find('.fc-
scroller')[0];
let ps = new PerfectScrollbar(elem);
}
},
header: {
left: 'title',
center: 'month, agendaWeek, agendaDay',
right: 'prev, next, today'
},
defaultDate: today,
selectable: true,
selectHelper: true,
views: {
month: {
// name of view
titleFormat: 'MMMM YYYY'
// other view-specific options here
},
week: {
titleFormat: ' MMMM D YYYY'
},
day: {
titleFormat: 'D MMM, YYYY'
}
},
eventLimit: true, // allow "more" link when
too many events
select: function(start: any, end: any) {
that.openEventForm();
},
eventClick: function(event, jsEvent) {
that.completeEventForm(event);
}
});
}, 500);
}
});
}
I expect the calendar to be populated the first time I navigate to the page.
Aside from refactoring the backend and eliminating the spaghetti code it wasn't a difficult issue once someone pointed out how the calendar inits. First the calendar has to grab onto the DOM element then it grabs the event source. If it doesn't grab the #calendar then it won't grab the event source until the next time it's initialized and at that point it is using the old event source data(if set up as my code was). "viewRender" needs to happen first, then "removeEvents" then "addEventSource".
getLocationEvents(location: PFLocation) {
if (location.events) {
return this.eventService
.getFaciltyTasks(location._id)
.subscribe(data => {
console.log(data);
this.facilityEvents = data;
});
}
}
getAllBatchEvents(location: PFLocation) {
return this.eventService
.getAllCultivationTasks(location._id)
.subscribe(data => {
console.log(data);
this.cultivationEvents = data;
});
}
getBatchEvents(batchId: string) {
return this.eventService.getBatchTasks(batchId).subscribe(data => {
console.log(data);
this.batchEvents = data;
});
}
editEventForm() {
this.state = 'editEvent';
}
getAllEvents(location: PFLocation) {
var that = this;
return new Promise(resolve => {
return this.eventService
.getAllLocationTasks(location._id)
.subscribe(data => {
console.log(data);
that.selectedEvents = data;
that.calInit();
resolve(that.selectedEvents);
});
});
}
calInit() {
var that = this;
const $calendar = $('#fullCalendar');
console.log(that.locationId);
if (this.selectedEvents) {
const today = new Date();
const y = today.getFullYear();
const m = today.getMonth();
const d = today.getDate();
$calendar.fullCalendar({
viewRender: function(view: any, element: any) {
// We make sure that we activate the perfect scrollbar when the view isn't on Month
if (view.name != 'month') {
var elem = $(element).find('.fc-scroller')[0];
let ps = new PerfectScrollbar(elem);
}
},
customButtons: {
filter: {
text: 'filter',
click: function() {
that.open();
}
}
},
// events: that.selectedEvents,
header: {
left: 'title',
center: 'filter, month, agendaWeek, agendaDay',
right: 'prev, next, today'
},
defaultDate: today,
selectable: true,
selectHelper: true,
views: {
month: {
// name of view
titleFormat: 'MMMM YYYY'
// other view-specific options here
},
week: {
titleFormat: ' MMMM D YYYY'
},
day: {
titleFormat: 'D MMM, YYYY'
}
},
eventLimit: true, // allow "more" link when too many events
select: function(start: any, end: any) {
that.openEventForm();
},
eventClick: function(event, jsEvent) {
that.eventLocation = new PFLocation({});
that.eventBatch = new Batch();
that.eventRoom = new Room();
that.viewEvent(event);
}
});
$calendar.fullCalendar('removeEvents');
$calendar.fullCalendar('addEventSource', that.selectedEvents);
}
}
ngOnInit() {
// const $calendar = $('#fullCalendar');
let that = this;
// that.filter = false;
this.sub = this.route.params.subscribe(params => {
that.locationId = params['locationid'];
if (that.locationId) {
that.AuthService.getCurrentUser().then(user => {
that.currentUser = user;
var locations = that.currentUser.locations.admin.concat(
that.currentUser.locations.user
);
var location = find(locations, function(location) {
return location._id == that.locationId;
});
console.log(location);
console.log(that.currentUser);
});
}
this.userService
.getLocation(this.locationId)
.subscribe(location => {
console.log('Out of on Init');
this.selectedLocation = JSON.parse(
JSON.stringify(location)
);
that.getAllEvents(this.selectedLocation);
console.log(this.selectedLocation);
});
console.log(this.selectedLocation);
});
}
I'm using an auto-run block where I re-execute the same mongo with a few session variables ! loop over those doc , construct an array of events then I call the addEventSource and refetchResources function which are pretty expensive computationally ! the fullcalendar becomes slow the more data ! on every action the auto-run block is rerun ! what in your in your opinion can be done to speed things up ? I thought about only re-rendering the delta elements but this doesn't cover the deletion and update .
calendar = $('#calendar').fullCalendar({
schedulerLicenseKey: Meteor.settings.public.fullCalendarLicenseKey,
now: new Date(),
editable: true, // enable draggable events
droppable: true, // this allows things to be dropped onto the calendar
aspectRatio: 1.8,
timezone:'local',
disableDragging: true,
displayEventTime: false,
selectable:true,
allDaySlot:true,
slotDuration:'24:00',
lazyFetching:true,
resourceLabelText: 'Employees',
nextDayThreshold:"12:00",
resources: function(callback) {
var tmp_obj = { usersSorting : { } };
tmp_obj.usersSorting["indexByLocation."+Session.get("locationId")] = 1;
var users = [];
var data = Meteor.users.find({
$or:[
{"profile.showInScheduler":{$exists:false}},
{"profile.showInScheduler":true}
],
assignedTo:{$in:[Session.get("locationId")]},
'locations._id':Session.get("locationId"),
"profile.companyId":Session.get("companyId")
},{sort : tmp_obj.usersSorting});
var arr = data.map(function(c) {
var employeeType = c.userSettings.employeeType;
var type = EmployeeType.findOne({_id:employeeType});
var img = Images.findOne({_id: c.picture});
var imgUrl = img ? img.url() : "/images/default-avatar.png";
c.name = c.name || "";
var totalHoursAllLocation = 0;
var totalHoursCurrentLocation = 0;
return {
id: c._id,
title: "t",
width:"2px"
};
});
callback(arr);
},
drop: function(date, jsEvent, ui, resourceId) {
},
eventResize: function( event, dayDelta, minuteDelta, revertFunc, jsEvent, ui, view ) {
},
dayClick: function(date, jsEvent, view,res,res2) {
},
eventClick: function ( event, jsEvent, view ) {
}
}).data().fullCalendar;
/********************* reactive calendar *****************/
this.autorun(function() {
if(Session.get("activeUsers")) {
schedulerSubs = Meteor.subscribe("SchedulesByLocation", Session.get("companyId"), Session.get("locationId"), Session.get("activeUsers"), moment(Session.get("currentDate")).startOf('week').toDate(), moment(Session.get("currentDate")).startOf('week').add(2, "weeks").endOf('isoweek').add(1,"days").toDate());
}
const company = Companies.findOne({_id: Session.get("companyId")});
Session.set("loading", true);
let events = [];
let usersInLocation = Meteor.users.find({
assignedTo: {$in: [Session.get("locationId")]},
'locations._id': Session.get("locationId"),
"profile.companyId": Session.get("companyId")
}).fetch();
let userIds = _.map(usersInLocation, "_id");
userIds.push("temp" + Session.get("companyId") + Session.get("locationId"));
Session.set("activeUsers",userIds);
if(schedulerSubs && schedulerSubs.ready()) {
var data;
SchedulerEvts = Schedules.find({
uid: {$in: userIds},
locationId: Session.get("locationId"),
companyId: Session.get("companyId"),
start: {$gte: moment(Session.get("currentDate")).startOf('week').toDate()},
end: {$lte: moment(Session.get("currentDate")).add(2, "week").endOf('isoweek').toDate()}
}).fetch();
SchedulerEvts.forEach(function (evt) {
var event = null;
var color = "";
var oloc = "";
var attendance = null;
var locationName = "";
var id = evt._id;
event = {
id:id,
type : evt.type,
title: evt.name,
start: evt.start,
end: evt.end,
color:color,
resourceId: evt.uid,
locationName:locationName,
};
events.push(event);
});
if (calendar) {
calendar.removeEvents();
calendar.addEventSource(events);
calendar.refetchResources();
}
}