I am doing some experiment using select2 js plugin inside a Vue js component, my mount() function looks like this
let self = this;
let url = self.context.recipes_autocomplete_url;
$(this.$refs.recipe_selection).select2({
minimumInputLength: 2,
ajax: {
dataType: 'json',
delay: 250,
cache: true,
url: function (params) {
return url;
},
data: function (params) {
let query = {
term: params.term
}
return query;
},
processResults: function (data, params) {
let more = (data.next != null)
if (more)
url = data.next;
else
url = self.context.recipes_autocomplete_url;
return {
results: data.results,
pagination: {
more: true
}
};
}
}
}).on("change.select2", function (e) {
let data = $(self.$refs.recipe_selection).select2('data')
if (data.length == 0)
return
// more staff here
});
My problem is with pagination, even if I hard code pagination:{more: true} the call to the next page never happen, I know this is not a common usage, but I am working on a legacy code, any idea?
I am using the last version of select2.js
Related
I builded a JQuery component to make a dropdown-accordion element. Each time i click on a item in a accordion, it will save the selection, close this accordion andopen the next one if exists.
To add data, it work as it :
$(window).ready(function () {
$(selector).data('dropdownaccordion').enqueueAccordion({ // Ajax parameter
name: "Commune",
data: {
url: "/trends/list",
method: 'GET',
datatype: "json",
timeout: 5000
}
},
{
name: "Batiment",
data: {
url: "/trends/list/"+this.path[0], // this.path[0] refer to the first selection, as this.path[1] will refer to the second etc
method: 'GET',
datatype: "json",
timeout: 5000
}
},
{ //Note that we can pass array instead of Ajax parameter
name: "Dummy",
data: ["One", "Two", "Three"]
})
});
I designed the component to work good with Rest API.
The problem is exposed for the second element i added. As you can see, i'm trying to pass this.path[0], refering to the first item selected. But the property path doesn't exist in the $(windows).ready scope, but in the $(selector).data('dropdownaccordion') scope.
I can replace it by $(selector).data('dropdownaccordion').path[0], but i want something more global, like ExpressJS do in URL (http://www.dummy.com/path/:item1/:item2 and replacing :itemx by the user selection)
Do you know a better solution, and if not, do you know a way to make it good ?
EDIT
My Component is designed as follow :
+function ($) {
'use strict';
/**
* Dropdown_Accordion CLASS DEFINITION
*/
function DropdownAccordion(component, ...accordions) {
this.accordions = [];
for(var i=0;i<accordions.length;i++){
this.accordions.push(accordions[i])
}
...
this.component = $(component);
...
// Render the accordions as DOM
this.render.call(this);
//Events
this.component
.on("click", ".accordion-item-body", $.proxy(function(event){
this.path.push($(event.target).text())
this.component.trigger('click.selection.dropdownaccordion', [$(event.target)])
this.openNext(event);
}, this))
.on('show.bs.dropdown', $.proxy(this.showMenu, this))
.on('shown.bs.dropdown', $.proxy(this.openNext, this))
.on('hide.bs.dropdown', $.proxy(function (event) {
this.component.find('.dropdown-menu').first().stop(true, true).slideUp();
this.component.find(".accordion-item .panel-collapse.collapse").each(function(){
$(this).collapse('hide');
});
this.opened = null;
(this.path.length !== this.accordions.length) ? this.component.trigger("abort.selection.dropdownaccordion", [this.path]):null
this.path = []
}, this));
}
DropdownAccordion.prototype = {
constructor: DropdownAccordion,
// Collapse accordion every time dropdown is shown
showMenu: function () {
// show the accordion
},
openNext: function (clickEvent) {
// Open the next accordion
},
render: function () {
// Will render the dropdown-accordion
// The following is how the AJAX request is performed
...
// When the accordion is opened, make the ajax request
DOMaccordion.on("open.accordion.dropdownaccordion", function () {
// The DOM element contains in data the options for the ajax request, or nothing if the accordion is an array
**$.ajax($(this).data('content.accordion.dropdownaccordion'))**
});
...
}
},
enqueueAccordion: function (...accordions) {
for(var i=0; i<accordions.length;i++)
this.accordions.push(accordions[i]);
this.render()
},
dequeueAccordion: function (name) {
this.accordions = this.accordions.filter(function (obj) {
return obj.name !== name;
})
this.render()
}
}
Look at the ** ** in the code, this is where the Ajax options is stored. I want that when i click on a item, there is a substitution on the .url to include the first item clicked.
I hope this seems clearer to you.
You can let enqueueAccordion accept a callback and pass the current accordion as a parameter:
DropdownAccordion.prototype = {
// ...
enqueueAccordion: function (makeAccordions) {
var accordions = makeAccordions(this);
for (var i = 0; i < accordions.length; i++)
this.accordions.push(accordions[i]);
this.render();
}
}
$(selector).data('dropdownaccordion').enqueueAccordion(function (_this) {
return [
{
name: "Batiment",
data: {
url: "/trends/list/" + _this.path[0],
method: 'GET',
datatype: "json",
timeout: 5000
}
];
});
If you want to use this directly, you can temporarily attach the callback to the current accordion:
DropdownAccordion.prototype = {
// ...
enqueueAccordion: function (makeAccordions) {
this.makeAccordions = makeAccordions;
var accordions = this.makeAccordions();
delete this.makeAccordions;
for (var i = 0; i < accordions.length; i++)
this.accordions.push(accordions[i]);
this.render();
}
}
$(selector).data('dropdownaccordion').enqueueAccordion(function () {
return [ // Ajax parameters
{
name: "Batiment",
data: {
url: "/trends/list/" + this.path[0],
method: 'GET',
datatype: "json",
timeout: 5000
}
}
];
});
I dug through the expressjs code, and found how they do the URL substituion. It work with the path-to-regex module. It seems not to be developped for browserside so i had to found another solution.
#aaron inspired me, and i finally add the possibility to have a callback in place of the url :
{
name: "Capteur",
data: {
url: function (path) {
return "/trends/list/" + path[0] + "/" + path[1]
},
method: 'GET',
datatype: "json",
timeout: 5000
}
}
By doing this, people are now able to modify the path based on the previous selection.
I use the select2 plugin from jquery and get my data over an ajax load. When I set the response I want to add attributes to the li-elements of my dropdown.
I already tried it with calling a function in "templateResult" but there I can only give back the vakue which is IN the <li></li> tags
My javascript:
var autocomplete = function () {
$("body").find("#myDropDown").select2({
language: "es",
ajax: {
url: searchDataUrl,
type: "POST",
// dataType: 'json',
delay: 250,
data: function (params) {
return {
term: params.term, // search term
page: params.page
};
},
processResults: function (data, params) {
return {
results: data.userData,
pagination: {
more: (params.page * 30) < data.total_count
}
};
},
cache: true
},
createTag: function (params) {
var term = $.trim(params.term);
if (term === '') {
return null;
}
return {
id: term,
text: term,
newTag: true // add additional parameters
}
},
escapeMarkup: function (markup) { return markup; },
minimumInputLength: 3,
templateResult: formatReponse, //With this it doesnt work
});
};
And the function from my templateResult Call:
//When I do this, I have a "<li>"-Tag within a "<li>"-Tag
var formatReponse = function (data) {
return '<li data-id="'+data.id+'" class="select2-results__option" role="treeitem">'+data.text+'</li>';
};
Can anybody help me with this? THANKS!
use the .attr(att,val) function like this:
Give your <li> an id name like liID in <li id='liID'> the following example
then give the name of the attribute you want to change in the example given as attributeToChange then give the value you want to set in the atribute in the example: valueToSet. good luck
$('#liID').attr('attributeToChange', 'valueToSet');
I have some code on a file that makes Ajax calls. This file is being called as a function by multiple other files that creates a new instance each time.
This is the JS code that is being called:
define(["underscore", "homeop", "domReady!"],
function (_, homeop, domready) {
var timeout = 500;
return function (opUrl, opList, onCallback) {
// IRRELEVANT CODE
var getFetch = function (optionName) {
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
}
});
};
self.getInfo = function (optionName) {
if (homeop.globalCache[optionName] === undefined) {
if (!_.contains(homeop.getOption(), optionName)) {
getFetch(optionName);
}
// MORE IRRELEVANT CODE GOES HERE
In other JS files, I call the get function; for example
var these = new getOptions(optionsUrl, optionsList, onLoadCallback);
var getOpt = these.get(OptionsUrl);
The problem is I am making multiple calls to the get information from the database causing multiple call to my JS file. Each new instance of the JS file will create a ajax call.
Is there a way to wait for all the calls to be done and then get data from the database? In other words how can I somehow combine all the call to my 'getOption.js'?
Thanks
Try this.. You can also implement queue in place of stack
var optionStack = [];
var isAvailable = true;
var getFetch = function (optionName) {
if(isAvailable){
isAvilable = false; // function not available now
}
else {
optionStack.push(optionName)
return;
}
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
},
done: function (){
isAvailable = true;
if(optionStack.length > 0){
getFetch(optionStack.pop());
}
}
});
};
I am using Select2 4.0.1, I have used ajax to populate the result based on users input, but whenever I search for anything select2 lists first page result, but consecutive pages were not loading, also request is made for 2nd page on scroll. seems to be I am missing something.
$multiselect = $(element).select2({
closeOnSelect: false,
multiple: true,
placeholder: 'Assign a new tag',
tags: true,
tokenSeparators: [","],
ajax: {
url: '/search_url',
dataType: 'json',
type: 'GET',
delay: 250,
data: function(params) {
return {
search: params.term,
page: params.page
};
},
processResults: function(data, params) {
var more, new_data;
params.page = params.page || 1;
more = {
more: (params.page * 20) < data.total_count
};
new_data = [];
data.items.forEach(function(i, item) {
new_data.push({
id: i.name,
text: i.name
});
});
return {
pagination: more,
results: new_data
};
},
cache: true
}
})
Any help is much appreciated.Thnx:)
This is the code I got working last week. I am using a different transport on my end, but that shouldn't make a difference. I was having the same issue as you regarding the lack of paging working while scrolling. My issue ended up being that I didn't have the proper {'pagination':{'more':true}} format in my processResults function. The only thing I can see that may work for you is to "fix" the page count in the data function vs. the processResults function.
When you scroll to the bottom of your list, do you see the "Loading more results..." label? Have you attempted to hard code the more value to true while debugging?
this.$(".select2").select2({
'ajax': {
'transport': function (params, success, failure) {
var page = (params.data && params.data.page) || 1;
app.do('entity:list:search',{'types':['locations'],'branch':branch,'limit':100,'page':page,'term':params.data.term})
.done(function(locations) {
success({'results':locations,'more':(locations.length>=100)});
});
}
, 'delay': 250
, 'data':function (params) {
var query = {
'term': params.term
, 'page': params.page || 1
};
return query;
}
, 'processResults': function (data) {
return {
'results': data.results
, 'pagination': {
'more': data.more
}
};
}
}
, 'templateResult': that.formatResult
, 'templateSelection': that.formatSelection
, 'escapeMarkup': function(m) { return m; }
});
I'm trying to set datas from ajax in a select2 select...
But the problem is that if I write something which isn't in my datas i can select this choice !
And this will take this value "I don't exist" ... The formatNoMatches() function seems not to be called ...
JS :
$(".select2-ajax").select2({
ajax: {
url: "ajax.call.php",
type:'POST',
dataType: 'json',
data: function (params) {
return {
nom: params.term, // search chars
page: params.page,
};
},
processResults: function (data, page) {
console.log(data.data);
if(typeof(data.data)=='undefined' || !data.data || data.data.length <= 0)
var res = [];
else
{
var res = [];
for (var i = data.data.length - 1; i >= 0; i--)
{
res.push({"text":data.data[i]["nom"]+' '+data.data[i]["prenom"],"id":data.data[i]["id_salarie"]});
};
}
return { results: res};
},
cache: true
},
formatNoMatches: function( term ) {
return "<li class='select2-no-results'>' "+term+" ': Aucun résultat</li>";
},
allowClear: true,
language: 'fr',
multiple: false,
I tried the two following after seeing THIS question : ( but still don't work )
selectOnBlur:false,
createSearchChoice: false,
escapeMarkup: function (markup) { return markup; },
minimumInputLength: 1,
});
This should only happen if you are returning an option from your server that matches the text the user entered or you are using the tags option.
Since you don't appear to be using tags, and your code doesn't include it, you can ensure this is not the issue by overriding createTag (previously createSearchChoice to always return null.
$('select').select2({
createTag: function () {
// Disable tagging
return null;
}
});
Set tags to false. Example:
$('select').select2({
tags: false
});