Select2 Programmatic Access - javascript

I am using jQuery Select2 and I am running into an issue setting a value and triggering an event.
I have a simple select2 dropdown hooked up to an Ajax source. This works perfectly fine.
I also have an event waiting for a select2 option to be chosen:
// On project select, we add the projects to the list along with the parties
$('.projSearch').on("select2-selecting", function(e) {
// Set the value of the project
var projectID = e.val,
table = '';
alert(projectID);
console.log(e);
...
When using the select2 dropdown like normal, this event works fine. It detects the data of the option you select.
However, I am also including a button on the page that allows a user to set the data of the field. It sets the data just fine, however it never triggers the event select2-selecting.
I tried passing the data along with the event but not matter what when the select2-selecting event is fired, it returns undefined.
$(document).on("click", "[name=addProject]", function() {
// Set the vars
var projectName = $(this).attr('projectname'),
projectID = $(this).attr('projectid'),
projectNameLong = projectName + ' ('+projectID+')';
// Add the project to the list
$("[name=projects]").select2("data", [{id: projectID, text: projectNameLong}]).trigger("select2-selecting", {val: projectID, data: {id: projectID, text: projectNameLong}});
});
How can I pass data along with the trigger to I can access it within the event?
Thanks for any info!

Select2 normally triggers the select2-selecting event by creating a $.Event object with the custom data containing the val and data attributes that you are looking for. The second parameter of .trigger will allow you to get extra data directly from within the event handler, but it doesn't attach it to the event object.
$(document).on("click", "[name=addProject]", function() {
// Set the vars
var projectName = $(this).attr('projectname'),
projectID = $(this).attr('projectid'),
projectNameLong = projectName + ' ('+projectID+')';
// Create the data object
var data = {
id: projectID,
text: projectNameLong
};
// Create the custom event object
var evt = $.Event("select2-selecting", {
val: data.id,
data: data
});
// Add the project to the list
$("[name=projects]")
.select2("data", [data])
.trigger(evt);
});
This should replicate the original select2-selecting event for you and allow you to reuse your event handler.

Related

Problem selecting an item after building the select options with AJAX

I use this javascript to select a specific option (the option value being specified within a hidden element):
$("select").each(function() {
var id = $(this).attr('id');
var source = 'input:hidden[name=select_'+id+']';
if ($(source).length) {
var selected = $(source).val();
$(this).val(selected).change();
}
});
This works fine when the options are hard coded in the HTML source.
I now need to populate the options with an AJAX call, I use the below method:
select : function(ctrl,id) {
var call = '/'+ctrl+'/'+$("#auth input[name=verify]").val();
$.getJSON(call, function(result) {
$.each(result, function() {
$('#'+id).append($("<option />").val(this.id).text(this.title));
});
});
},
I process the select method (AJAX) on page load, and the options populate fine. But when I then try to select the desired option, the browser defaults to the first option.
I have tested what is happening by sticking some alerts around the code as thus:
alert($(this).val(selected)); // A
alert($(this).val()); // B
$(this).val(selected).change();
alert($(this).val()); // C
When the options are hard coded I get A=3, B=null, C=3 i.e. it works
When the options are populated via AJAX I get A=3, B=null, C=null i.e. it fails
I am guessing that I need to trigger some kind of change() event after populating the option list with AJAX. I have tried (a bit overkill I know):
$('#'+id).append($("<option />").val(this.id).text(this.title).change());
&
$('#'+id).append($("<option />").val(this.id).text(this.title)).change();
Any ideas? Thx
Problem solved.
Although I was triggering the code in the correct order (in theory), because of javascripts event driven behaviour the AJAX call was not completing until after my select initialisation had finished. So I moved the code to set the selected option into the AJAX call and voila.
select : function(ctrl,id) {
var call = '/'+ctrl+'/'+$("#auth input[name=verify]").val();
$.getJSON(call, function(result) {
$.each(result, function() {
$('#'+id).append($("<option />").val(this.id).text(this.title));
});
var source = 'input:hidden[name=select_'+id+']';
if ($(source).length) {
var selected = $(source).val();
$('#'+id).val(selected).change();
}
});

GTM issue with double event created instead of dl push

I use this code in GTM , that retrieves a number from another domain and stores it on a dataLayer value, with a dL.push. I want the variable to be available on a specific event.
(function ()
{
var callbackMethodName = "adnscallback";
window[callbackMethodName] = function(data) {
(function() {
dataLayer.push({
'event': 'ga_new',
"id2": data.uid
});
})();
}
var sc = document.createElement("script");
sc.id = "script_" + callbackMethodName;
sc.src = "https://example.site.com/getnumber?callback=" + callbackMethodName;
document.body.appendChild(sc);
})();
But I already create an event called ga_new (hardcoded, that creates all sort of values on the page) and when this codes run, it creates another event called ga_new, instead of pushing the values on the existing event. This creates issues with the tags as they are double firing.
What iam doing wrong and the push, instead of appending the data, it creates the event again?
You can not "update" a custom event. The "event" keyword is a signal to GTM that it needs to update its internal data structure with new values.
The datalayer variable in the page is an array of objects, the internal datastructure is a single object into which new values are merged, and existing values for the same keys are overwritten. GTM overwrites the native implementation of the JS "push" method with its own code that watches for the "event" keyword. So every time it encounters the "event" key changes are triggered.
You either need a different name for the event, or you change the trigger so that it only fires when both the "ga_new" event are set and the data.uid field is set.

execute code after selection from dropdown

I am building a meteor based webapp. One of the pages has a drop down menu, which the user has to select options (various school districts) from. The selection needs to be detected, followed by querying the database filtering documents based on the selection and counting the documents returned, followed by rendering a template (a chart built using highcharts.js)
Code as follows:
Template.districtDropdown.events({
'change' : function(event, template){
event.preventDefault();
var selectedValue = template.$("#selectDistrict").val();
console.log("You Selected " + selectedValue);
var filter = {
find: {
'School District' : selectedValue
}
};
Meteor.subscribe('aggByDistrict', filter);
productNames2 = _.uniq(CombinedData.find().map( function(doc) { return doc.Product; }));
console.log(productNames2);
var productValues2 = [];
for(var i = 0; i < productNames2.length; i++) {
productValues2.push(CombinedData.find({'Product' : productNames2[i]}).count())
};
console.log(productValues2);
}
});
I'm facing three issues.
The console on the client side throws an error "productNames2" has not been defined as soon as the page loads, pointing to the line which has the for loop (even before I've made any selection).
The first time I click on one of the options in the drop down menu, I get empty arrays (the two console.log(productNames2) and console.log(productValues2), but when I click on some other option, it works the second time. No idea why.
I want to render a template {{> highchart2}} after the user has selected an option from the drop down and the two arrays (productNames2, productValues2) have been populated.
Can anyone give me ideas on how I can go about resolving these issues?
Several problems with your code
Subscribe needs to be put in Template.districtDropdown.created. If you subscribe during the events, there might be the postpone during the subscription and no data available during the events
event should be attached to a DOM component. As in change #selectDistrict and then, you select the value like this var selectedValue = $(event.target).val();

Removing all the eventSources in fullCalendar

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

How to pass data in a button event handler on a Google script extending a spreadheet?

Extending a Google Spreadsheet, I run a script showing some data in a sidebar. At the bottom I want to add a button to mail the data.
However I can't figure out how the data can be passed from button to handler:
There's no possibility to pass data into the event call;
There's no way to get the button object from the event info, I can merely get the ID, which is useless if I can't get to the uiInstance (created outside of the handler function).
So what's the trick?
You have to add a callback element (possibly a panel wrapping everything you need) to the server handler before assigning it to the button. For example:
function myFunction() {
var app = UiApp.createApplication();
var panel = app.createVerticalPanel();
panel.setId('myPanel').add(
app.createTextBox().setName('boxExample')).add(
app.createListBox().setName('listExample').addItem('A').addItem('B'));
// ↓↓ this is what you need ↓↓
var handler = app.createServerHandler('callbackFunction').addCallbackElement(panel);
var btn = app.createButton(btn, handler);
app.add(panel.add(btn));
//show app...
}
function callbackFunction(e) {
var app = UiApp.getActiveApplication();
app.getElementById('myPanel').add(
app.createLabel(e.parameter.boxExample)).add(
app.createLabel(e.parameter['listExample']));
return app;
}
Using PropertiesService
I found (I don't know how) Google Script offers a data storage service called PropertiesService.
Assuming, as in this case, the data is for user only, I would need to first store the data as such:
var userProperties = PropertiesService.getUserProperties()
userProperties.setProperty("myKey", "myValue")
// Note myValue will be a string, so to store an array,
// you'd need JSON.stringify(myArray)
Then as the button handler is called, the script can retrieve the data easily:
var userProperties = PropertiesService.getUserProperties()
var myValue = userProperties.getProperty("myKey")
Using Hidden Widget
An alternative seems to be the use of a "hidden" widget.
function doGet() {
var app = UiApp.createApplication();
// Note that the name "appState" for callbacks, and the id "hidden" for
// getting a reference to the widget, are not required to be the same.
var hidden = app.createHidden("appState", "0").setId("hidden");
app.add(hidden);
var handler = app.createServerHandler("click").addCallbackElement(hidden);
app.add(app.createButton("click me!", handler));
app.add(app.createLabel("clicked 0 times").setId("label"));
return app;
}
function click(eventInfo) {
var app = UiApp.createApplication();
// We have the value of the hidden field because it was a callback element.
var numClicks = Number(eventInfo.parameter.appState);
numClicks++;
// Just store the number as a string. We could actually store arbitrarily complex data
// here using JSON.stringify() to turn a JavaScript object into a string to store, and
// JSON.parse() to turn the string back into an object.
app.getElementById("hidden").setValue(String(numClicks));
app.getElementById("label").setText("clicked " + numClicks + " times");
return app;
}
(code from linked reference)

Categories