I am using select2 in an express app to make an input box where users can select subjects from a list, and can update this list with any newly added options.
The thing I'm struggling with is that select2
runs client-side, whereas any data I use to seed my <option>
tags (that I want to append new options to) is server-side.
I want users to be able to add subjects that don't exist in the original list, so that future users will be presented with newly added options (as well as the original ones)
These are the options I've considered for achieving this (in increasing desirability):
<option>Subject</option>
html tags for each added tag<option>
s from this array<option>
from a json
object, and update this object on tag creation<option>
from an external database (e.g. mongoose), and update this on tag creationAs far as I can see, all of these options require that my client-side code (select2-js
) talks to server-side code (where my array, .json
file or mongoose
schema would be), and I have no idea how to go about doing this.
In my current approach I am attempting to to specify a "local" json
file as my data source in my select2
call (see here). However, this doesn't seed the database with any options, so this isn't working as I expected.
I then check if each new tag exists in an array (dataBase
), and add it to the database if not:
// Data to seed initial tags:
var dataBase = [
{ id: 0, text: 'Maths'},
{ id: 1, text: 'English'},
{ id: 2, text: 'Biology'},
{ id: 3, text: 'Chemistry'},
{ id: 4, text: 'Geography'}
];
$(document).ready(function() {
$('.select2-container').select2({
ajax: {
url: '../../subjects.json',
dataType: 'json',
},
width: 'style',
multiple: true,
tags: true,
createTag: function (tag) {
var isNew = false;
tag.term = tag.term.toLowerCase();
console.log(tag.term);
if(!search(tag.term, dataBase)){
if(confirm("Are you sure you want to add this tag:" + tag.term)){
dataBase.push({id:dataBase.length+1, text: tag.term});
isNew = true;
}
}
return {
id: tag.term,
text: tag.term,
isNew : isNew
};
},
tokenSeparators: [',', '.']
})
});
// Is tag in database?
function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].text.toLowerCase() === nameKey.toLowerCase()) {
return true
}
}
return false
};
However, this approach will add the new tags to an array that is destroyed once I refresh the page, and new tags are not stored.
How can I modify this to load server-side data (json
, mongoose
document or anything else that is considered a best practice), and update this data with newly added options (that pass my tests)?
New options can be added to a Select2 control programmatically by creating a new Javascript Option object and appending it to the control: var data = { id: 1, text: 'Barn owl' }; var newOption = new Option(data. text, data.id, false, false); $('#mySelect2'). append(newOption).
HTML. Create a <select class="select2_el" > element to initialize select2 on page load and create <div id="elements" > container to store <select > element on button click using jQuery AJAX.
var initial_creditor_id = "3"; $(". creditor_select2"). select2({ ajax: { url: "/admin/api/transactions/creditorlist", dataType: 'json', delay: 250, data: function (params) { return { q: params. term, c_id: initial_creditor_id, page: params.
Select2 gives you a customizable select box with support for searching, tagging, remote data sets, infinite scrolling, and many other highly used options.
On your server-side, you can have an api that maintains and returns the tag array. If you want the array to persist even after server shutdown, you can store the tags array in a database.
Server side:
let dataBase = [
{ id: 0, text: 'Maths'},
{ id: 1, text: 'English'},
{ id: 2, text: 'Biology'},
{ id: 3, text: 'Chemistry'},
{ id: 4, text: 'Geography'}
];
//Assuming you have a nodejs-express backend
app.get('/tags', (req,res) => {
res.status(200).send({tags: dataBase});
} );
Client Side:
$(document).ready(function() {
dataBase=[];
$.get("YOUR_SERVER_ADDRESS/tags", function(data, status){
console.log("Data: " + data + "\nStatus: " + status);
dataBase = data;
});
$('.select2-container').select2({
data: dataBase,
placeholder: 'Start typing to add subjects...',
width: 'style',
multiple: true,
tags: true,
createTag: function (tag) {
var isNew = false;
tag.term = tag.term.toLowerCase();
console.log(tag.term);
if(!search(tag.term, dataBase)){
if(confirm("Are you sure you want to add this tag:" + tag.term)){
dataBase.push({id:dataBase.length+1, text: tag.term});
isNew = true;
//Update the tags array server side through a post request
}
}
return {
id: tag.term,
text: tag.term,
isNew : isNew
};
},
tokenSeparators: [',', '.']
})
});
// Is tag in database?
function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].text.toLowerCase() === nameKey.toLowerCase()) {
return true
}
}
return false
};
You can use select2:select
and select2:unselect
event for this.
var dataBase = [{
id: 0,
text: 'Maths'
},
{
id: 1,
text: 'English'
},
{
id: 2,
text: 'Biology'
},
{
id: 3,
text: 'Chemistry'
},
{
id: 4,
text: 'Geography'
}
];
$(document).ready(function() {
$('.select2-container').select2({
data: dataBase,
placeholder: 'Start typing to add subjects...',
width: 'style',
multiple: true,
tags: true,
createTag: function(tag) {
return {
id: tag.term,
text: tag.term,
isNew: true
};
},
tokenSeparators: [',', '.']
})
$(document).on("select2:select select2:unselect", '.select2-container', function(e) {
var allSelected = $('.select2-container').val();
console.log('All selected ' + allSelected);
var lastModified = e.params.data.id;
console.log('Last Modified ' + lastModified);
var dbIdArray = dataBase.map((i) => i.id.toString());
var allTagged = $('.select2-container').val().filter((i) => !(dbIdArray.indexOf(i) > -1))
console.log('All Tagged ' + allTagged);
});
});
.select2-container {
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<select class="select2-container"></select>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With