Removing all the eventSources in fullCalendar - javascript

I have two types of events in my fullCalendar. Few are the fetched from the eventSources using :
$('calendar').fullCalendar('addEventSource' , 'source')
And few are created by the user. I am using
$('calendar').fullCalendar('renderEvent', eventData, true)
Now upon clicking a button I want to remove all the events that are obtained from the eventSources and retain those that are created by the user.
I tried doing :
$('calendar').fullCalendar('removeEventSource' , function(e){ return true ; } ) ;
But that doesn't work. How do I achieve doing the job ?

You can simply call:
$('#calendar').fullCalendar('removeEventSources');

I did exactly what you want to do in a recent project.
Fullcalendar supports nonstandard fields.
Non-standard Fields
In addition to the fields above, you may also include your own
non-standard fields in each Event Object. FullCalendar will not modify
or delete these fields. For example, developers often include a
description field for use in callbacks such as eventRender.
Source
So you could do something like
//Save user created event
$('#calendar').fullCalendar('renderEvent', {
title: title,
end: end,
start: start,
editable : true,
//nonstandard field
isUserCreated: true,
description: description,
});
then to remove events that hasn't been created by user
//Get all client events
var allEvents = $('#calendar').fullCalendar('clientEvents');
var userEventIds= [];
//Find ever non usercreated event and push the id to an array
$.each(allEvents,function(index, value){
if(value.isUserCreated !== true){
userEventIds.push(value._id);
}
});
//Remove events with ids of non usercreated events
$('#calendar').fullCalendar( 'removeEvents', userEventIds);
or if you need less control then simply (as #A1rPun suggested)
$('#calendar').fullCalendar( 'removeEvents', function(e){ return !e.isUserCreated});

They added ways to remove both event sources and events in event calendar, as long as you're using 2.8.0.
To remove all event sources or all events from full calendar, do the following:
$('#calendar').fullCalendar( 'removeEventSources', optionalSourcesArray)
If optionalSourcesArray isn't defined, it simply removes all event sources. In my case, I needed to remove event sources, so I called:
$('#calendar').fullCalendar( ‘removeEvents’, idOrFilter )
See the documentation for both method calls here:
https://fullcalendar.io/docs/removeEventSources
https://fullcalendar.io/docs/removeEvents
You can read more about the original removeEventSources pull request and how it's actually implemented here:
https://github.com/fullcalendar/fullcalendar/issues/948

Related

Using FullCalendar, how to add information to EventObject when eventReceive?

I've started discovering and using FullCalendar but I'm stuck with it.
What I want to do is a ResourceTimeline in Month view, with external event dragging (a left panel).
The subject later would be to have a modal when you drop an event, in order to choose if you want the event to be from 8am to 12pm, or afternoon from 12pm to 6pm.
So first, I'd like to do a simple eventReceive without modal, to see if I can update the event when it's dropped.
But it seems I can't, what do I do wrong ?
From what I can understand, it looks like when you drop an event in month view, the event in the param sent to eventReceive is modified.
eventReceive(info) {
info.event.start = moment(info.event.start).add(8, 'hours').format('YYYY-MM-DD hh:mm:ss');
// var c = confirm('OK = morning, Cancel = aprem');
// if (c) {
// console.log("morning !")
// } else {
// console.log("afternoon !")
// }
}
Events are very basic because I wanted to complete them whenever I drop them into the calendar
new Draggable(listofEvents, {
itemSelector: '.draggable',
eventData(event) {
return {
title: event.innerText,
activite: event.dataset.activite,
allDayDefault: false,
}
},
})
I even tried to force allDayDefault to false but it doesn't change a thing...
Here is the codepen of the project in its current state : https://codepen.io/nurovek/pen/zYYWGyX?editors=1000
Sorry if my post lacks information, I'm not used to ask questions on SO. If it's lacking, I'll try to be more explicit if you ask me, of course !
As per the documentation, an event's public properties (such as "start", "end", title" etc) are read-only. Therefore to alter a property after the event is created you must run one of the "set" methods.
So your idea will work if you use the setDates method:
eventReceive(info) {
info.event.setDates(moment(info.event.start).add(8, 'hours').toDate(), info.event.end, { "allDay": false } )
console.log(info.event);
}
Demo: https://codepen.io/ADyson82/pen/dyymawy?editors=1000
P.S. You might notice I also made a few other little changes to your CodePen, mainly to correct all the links to CSS and JS files, since it was generating all sorts of console errors. These errors were because links were wrong or simply referred to something non-existent, and for some reason you were also using files from two different versions of fullCalendar (4.3.0 and 4.3.1), which is never a good idea if you want to ensure full compatibility.

Programmatically set the value of a Select2 ajax

I have a Select2 auto-complete input (built via SonataAdmin), but cannot for the life of me figure out how to programmatically set it to a known key/value pair.
There's a JS Fiddle here that shows roughly what I have. What I want to know is what function I can attach to the button so that
the Select2 field shows the text "NEW VALUE" to the user, and
the Select2 field will submit a value of "1" when the form is sent to the server
I have tried all sorts of combinations of jQuery and Select2 data and val methods, called against various inputs on the page, but nothing seems to work... surely there's some way to do this?
-- Edit --
The accepted answer below is very useful, helps shed some light on the right way to initialise the selection and explains what initSelection is for.
Having said that, it seems that my biggest mistake here was the way I was trying to trigger the change.
I was using:
$(element).select2('data', newObject).trigger('change');
But this results in an empty add object inside select2's change event.
If, instead, you use:
$(element).select2('data', newObject, true);
then the code works as it should, with the newObject available in select2's change event and the values being set correctly.
I hope this extra information helps somebody else!
Note this was tested with version 4+
I was finally able to make progress after finding this discussion: https://groups.google.com/forum/#!topic/select2/TOh3T0yqYr4
The last comment notes a method that I was able to use successfully.
Example:
$("#selectelement").select2("trigger", "select", {
data: { id: "5" }
});
This seems to be enough information for it to match the ajax data, and set the value correctly. This helped immensely with Custom Data Adapters.
Note: For multi select, execute the above code for each item, like this :
// for each initially selected ids, execute the above code to add the id to the selection.
[{id: 5, text: 'op5'}, {id: 10, text: 'op10'}].forEach(option => {
$("#selectelement").select2("trigger", "select", {data: { id: option.id, text: option.text }});
})
Note: The Question and this Answer are for Select2 v3. Select2 v4 has a very different API than v3.
I think the problem is the initSelection function. Are you using that function to set the initial value? I know the Select2 documentation makes it sound like that is it's purpose, but it also says "Essentially this is an id->object mapping function," and that is not how you have implemented it.
For some reason the call to .trigger('change') causes the initSelection function to get called, which changes the selected value back to "ENABLED_FROM_JS".
Try getting rid of the initSelection function and instead set the initial value using:
autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});
jsfiddle
Note: The OP has supplied the formatResult and formatSelection options. As supplied, those callback functions expect the items to have a "label" property, rather than a "text" property. For most users, it should be:
autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});
More info on the initSelection function:
If you search through the Select2 documentation for "initSelection", you will see that it is used when the element has an initial value and when the element's .val() function is called. That is because those values consist of only an id and Select2 needs the entire data object (partly so it can display the correct label).
If the Select2 control was displaying a static list, the initSelection function would be easy to write (and it seems like Select2 could supply it for you). In that case, the initSelection function would just have to look up the id in the data list and return the corresponding data object. (I say "return" here, but it doesn't really return the data object; it passes it to a callback function.)
In your case, you probably don't need to supply the initSelection function since your element does not have an initial value (in the html) and you are not going to call its .val() method. Just keep using the .select2('data', ...) method to set values programmatically.
If you were to supply an initSelection function for an autocomplete (that uses ajax), it would probably need to make an ajax call to build the data object.
To set initial values you need to add the necessary options tag to the select element with jQuery, then define these options as selected with select2's val method and finally trigger select2's 'change' event.
1.-$('#selectElement').append('<option value=someID>optionText</option>');
2.-$('#selectElement').select2('val', someID, true);
The third boolean argument tells select2 to trigger the change event.
For more info, see https://github.com/select2/select2/issues/3057
Be carreful, there is a mistake in "validated" comment.
autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});
The correct way is
autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});
Use text instead of label
With Select2 version 4+, there is actually nothing special you need to do. Standard jQuery with a 'change' event trigger at the end will work.
var $select = $("#field");
var items = {id: 1, text: "Name"}; // From AJAX etc
var data = $select.val() || []; // If you want to merge with existing
$(items).each(function () {
if(!$select.find("option[value='" + this.id + "']").length) {
$select.append(new Option(this.text, this.id, true, true));
}
data.push(this.id);
});
$select.val(data).trigger('change'); // Standard event notifies select2
There is a basic example in the Select2 documentation:
https://select2.org/programmatic-control/add-select-clear-items
from their examples
https://select2.github.io/examples.html
Programmatic access:
var $example = $(".js-example-programmatic").select2();
var $exampleMulti = $(".js-example-programmatic-multi").select2();
$(".js-programmatic-set-val").on("click", function () { $example.val("CA").trigger("change"); });
$(".js-programmatic-open").on("click", function () { $example.select2("open"); });
$(".js-programmatic-close").on("click", function () { $example.select2("close"); });
$(".js-programmatic-init").on("click", function () { $example.select2(); });
$(".js-programmatic-destroy").on("click", function () { $example.select2("destroy"); });
$(".js-programmatic-multi-set-val").on("click", function () { $exampleMulti.val(["CA", "AL"]).trigger("change"); });
$(".js-programmatic-multi-clear").on("click", function () { $exampleMulti.val(null).trigger("change"); });
All you have to do is set the value and then execute: $ ('#myselect').select2 (); or $ ('select').select2 ();.
And everything is updated very well.
If you remove the .trigger('change') from your fiddle it logs Object {id: 1, label: "NEW VALUE"} (need to click twice since the logging is before the value change). Is that what you're looking for?
When using select2 with multiple option, use this construction:
$(element).select2("data", $(element).select2("data").concat(newObject), true);
jqueryselect2multiplesetconcatenation
this is it:
$("#tag").select2('data', { id:8, title: "Hello!"});
FOR VERSION 3.5.3
$(".select2").select2('data',{id:taskid,text:taskname}).trigger('change');
Based on John S' answer . Just the the above will work however only if while initializing the select2 the initSelection option is not initialized.
$(".select2").select2({
//some setup
})
For those still using version 3.5 or even higher ones. Please be sure how you reference select2.js to your page. If you are using async or defer load. This plug-in might behave differently.
Thought to mention.
In my situation I was able to render the preselected option into the HTML server side with PHP.
During my page load, I already knew the option value, so my <select name="team_search"></select> became the following;
<select name="team_search">
<?php echo !empty($preselected_team)
? '<option selected="selected" value="'. $preselected_team->ID .'">' . $preselected_team->team_name . '</option>'
: null ?>
</select>';
As you can see, when I have a $preselected_team available I render in an option with the selected attribute, value and label set. And, if I don't have a value then not option is rendered.
This approach may not always be possible (and in the case of the OP is not mentioned), but it does come with the added benefit of being ready on page load ahead of JavaScript execution.
Append a new option with id and text
let $newOption = $("<option selected='selected'></option>").val(1).text('New Text goes here');
$("#selector").append($newOption).trigger('change');

How to register onClick listener to dijit Button within GridX?

I'm trying to register my onClick listener to dijit Button placed as in-cell widget withing GridX. I've done the following, basing on example test_grid_cellWidget:
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit.form.Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.connect("onClick", function(){
alert('clicked')
})
}
},
setCellValue is executed successfully, and the label is changed. However, the onClick listener is not registered and is not called, when I click on button. When I use the syntax data-dojo-props="onClick:function" it works, but it requires declaring listener function as global, which is something I'd like to avoid.
Anyway, I have the Button object, and I'm executing the code found in dijit documents, so it should be working. But why nothing is registered in that context?
I've found the answer in GridX wiki: https://github.com/oria/gridx/wiki/How-to-show-widgets-in-gridx-cells%3F
You need to use the field cellWidget.btn._cnnt:
setCellValue: function(gridData, storeData, cellWidget){
this.btn.set("label", "Speichern")
if(cellWidget.btn._cnnt){
// Remove previously connected events to avoid memory leak.
cellWidget.btn._cnnt.remove();
}
cellWidget.btn._cnnt = dojo.connect(cellWidget.btn, 'onClick', lang.hitch(cellWidget.cell, function(){
rowSaveClick(this.row)
}));
},
I don't know what dojo version you use, but as you use data-dojo-type, I suppose it's 1.7+.
First, I would recommend to drop the dot notation of module names and start using the AMD mid syntax instead (i.e.: drop "dijit.form.Button" for "dijit/form/Button", as the dot notation will be dropped in dojo 2.0).
Then, the recommended way of connecting events to widgets is to :
either define the event as a function (like widget.onClick = function(evt){...})
or use the "on" method of the widget (like widget.on("click", function(evt){...}))
I prefer to use the second form, as it's more consistent with dojo/on. It consists of using the event name without the "on", and put everything in lowercase. For example, if your widget had an extension point named "onMouseRightClick", you could use it as widget.on("mouserightclick", ...)
Your example would then become :
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit/form/Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.on("click", function(){
alert('clicked')
});
}
},
Note : untested code. I'm just guessing what the problem might be. Let me know if there is still an issue...
I've found that using getCellWidgetConnects works quite well (see docs).
But the docs aren't exactly clear, so it wasn't working for me at first. If you are connecting to a DomNode, the pass 'click' as the event in the connections array. If you are connecting to a Dijit widget, then pass 'onClick'.

FullCalendar - After initial load, dynamically updating ajax parameters not working

I'm working with http://arshaw.com/fullcalendar/ and I would like to dynamically filter the events shown based on various checkboxes on the page. I am using an ajax source (with filters passed as parameters) to gather data.
The problem I am running into is once I load the calendar, I cannot, for the life of me (or stackoverflow searches) figure out how to update the parameters. It seems once the calendar is loaded, those parameters are "baked" and cannot be changed.
I have tried every combination of addEventSource, removeEventSources, removeEvents, refetchEvents, etc (as recommended here: rerenderEvents / refetchEvents problem), with still no luck.
My current solution is to re-initiate the entire .fullCalendar every time a filter is updated-- this is leading to tons of issues as well and really isn't an elegant solution.
Any ideas on a simpler way to do this? Refetching your source with updated parameters each time should be automatic. I really do appreciate your help.
In my code i do like that :
I have an array with the calendars id to display and i update it when the user check or uncheck the checkbox.
In fullCalendar initialization I retrieve all events and i filter them with this function :
function fetchEvent( calendars, events) {
function eventCorrespond (element, index, array) {
return $.inArray(element.calendarid, calendars) > -1;
}
return events.filter(eventCorrespond);
}
$('#calendar').fullCalendar({
events: function(start, end, callback) {
//fetch events for date range on the server and retrieve an events array
//update calendars, your array of calendarsId
//return a filtered events array
callback(fetchEvent(calendars , events));
}
});
and when the user check or uncheck a checkbox i do :
$('#calendar').fullCalendar('refetchEvents');
The solution that works for me is:
$('#calendar').fullCalendar('removeEventSource', 'JsonResponse.ashx?technicans=' + technicians);
technicians = new_technicians_value;
$('#calendar').fullCalendar('addEventSource', 'JsonResponse.ashx?technicans=' + technicians);
After "addEventSource" events will be immediately fetched from the new source.
full answer here https://stackoverflow.com/a/36361544/5833265

How do I delete this event from FullCalendar?

The calendar lets the user drag a timeslot onto the calendar, however I would like them to be able to remove it if they click on it.
So in the eventClick I have this function:
function (calEvent) {
removeRequestedEvent($(this), calEvent);
},
It just passes in the calendar event and the calendar itself.
removeRequestedBooking: function (cal, calEvent) {
if (!confirm("Delete?"))
return;
cal.fullCalendar("removeEvents", calEvent.id);
cal.fullCalendar("rerenderEvents");
// Re-show draggable element
$("#requests #" + calEvent.id).show();
}
I've also tried using a filter, but a breakpoint on the return statement is never hit.
cal.fullCalendar("removeEvents", function (event) {
return event.id == calEvent.Id;
});
Any ideas? (I know the Id is right, and the last line works). Firebug doesn't show any errors in the javascript.
I'm using FullCalendar v1.4.10
When you have all your id's in place use Tuan's solution.
But when you do NOT have id's in your event do it like this (this work also when you have id's set):
eventClick: function(event){
$('#myCalendar').fullCalendar('removeEvents',event._id);
}
Why this problem appear?
The common reason for that is fullcalendar doesn't add id automatically when you're adding new event. If so, id which you have passed is undefined. Fullcalendar uses id in both cases when you're trying delete using id or filter. So when it's value is undefined it always return false. Meaning list of elements to delete is always empty.
Even simpler:
eventClick: function(calEvent, jsEvent, view) {
$('#calendar').fullCalendar('removeEvents', function (event) {
return event == calEvent;
});
}
Instead of using your passed in cal, can you try using a call to the div that holds your calendar?
In the case of eventClick, this refers to the HTML for the event according to what I'm reading in the docs.
Use refetchEvents:
cal.fullCalendar("refetchEvents");
Justkt's answer took me a second to wrap my head around, but I'll post my results for any other noobs who need to see the code in a really simple way:
eventClick: function(event){
var event_id = event.id;
$.post('/Dropbox/finance/index.php/welcome/update', {"event_id": event_id},
function(data){
$('#calendar').fullCalendar("removeEvents", (data));
$('#calendar').fullCalendar("rerenderEvents");
}
});
}
The PHP (using codeignighter):
public function update(){
$result = $this->input->post('event_id');
echo $result;
// would send result to the model for removal from DB, or whatever
}
I use filter function with event.start and it works well
calendar.fullCalendar('removeEvents', function(event) {
return
$.fullCalendar.formatDate(event.start, 'yyyyMMdd')
== $.fullCalendar.formatDate(start, 'yyyyMMdd');
});

Categories