admin管理员组文章数量:1327257
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):
- Add new
<option>Subject</option>
html tags for each added tag - Push new tags to an array, and seed the
<option>
s from this array - Seed the
<option>
from ajson
object, and update this object on tag creation - Seed the
<option>
from an external database (e.g. mongoose), and update this on tag creation
As 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)?
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):
- Add new
<option>Subject</option>
html tags for each added tag - Push new tags to an array, and seed the
<option>
s from this array - Seed the
<option>
from ajson
object, and update this object on tag creation - Seed the
<option>
from an external database (e.g. mongoose), and update this on tag creation
As 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)?
- 1 Use ajax to populate the json on the page. Then use the json to populate the select2 as you are currently doing. Attach the json to document.ready and to the database update to get your result – Lelio Faieta Commented Mar 18, 2019 at 11:00
- @LelioFaieta - thanks for the pointers. Any chance you could pad this out as an answer? – fugu Commented Mar 18, 2019 at 11:02
3 Answers
Reset to default 5 +50On 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./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare./ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<select class="select2-container"></select>
Here's what I've ended up with (thanks to both answers):
1. Set up a Mongoose DB to hold subjects:
models/subjects.js
var mongoose = require("mongoose");
var SubjectSchema = new mongoose.Schema({
subject: { type: String },
});
module.exports = mongoose.model("Subjects", SubjectSchema);
2. Set up api routes in node js express backend:
routes/api.js
var express = require("express");
var router = express.Router();
var Subjects = require("../models/subjects");
// GET route for all subjects in db
router.get("/api/subjects/all", function(req, res){
Subjects.find().lean().exec(function (err, subjects) {
return res.send(JSON.stringify(subjects));
})
});
// POST route for each added subject tag
router.post("/api/subjects/save", function(req, res){
var newSubject = {};
newSubject.subject = req.body.subject;
console.log("Updating db with:" + newSubject);
var query = {subject: req.body.subject};
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
// Find the document
Subjects.findOneAndUpdate(query, options, function(error, subject) {
if (error) return;
console.log("Updated db enry: " + subject);
});
return res.send(newSubject);
});
3. Set up select2
input field:
public/js/select2.js
var dataBase=[];
$(document).ready(function() {
// Get all subjects from api (populated in step 2) and push to dataBase array
$.getJSON('/api/subjects/all')
.done(function(response) {
$.each(response, function(i, subject){
dataBase.push({id: subject._id, text: subject.subject});
})
console.log("dataBase: " + dataBase);
})
.fail(function(err){
console.log("$.getJSON('/api/subjects/all') failed")
})
// Get data from api, and on 'selecting' a subject (.on("select2:select"), check if it's in the dataBase. If it is, or the user confirms they want to add it to the database, send it to POST route, and save it to our Subjects db.
$('.select2-container')
.select2({
ajax: {
url : "/api/subjects/all",
dataType: 'json',
processResults: function (data) {
return {
results: $.map(data, function(obj) {
return { id: obj._id, text: obj.subject };
})
};
}
},
placeholder: 'Start typing to add subjects...',
width: 'style',
maximumSelectionLength: 5,
multiple: true,
createTag: function(tag) {
return {
id: tag.term,
text: tag.term.toLowerCase(),
isNew : true
};
},
tags: true,
tokenSeparators: [',', '.']
})
.on("select2:select", function(e) {
if(addSubject(dataBase, e.params.data.text)){
console.log(e.params.data.text + " has been approved for POST");
ajaxPost(e.params.data.text)
} else {
console.log(e.params.data.text + " has been rejected");
var tags = $('#selectSubject select').val();
var i = tags.indexOf(e.params.data.text);
console.log("Tags: " + tags);
if (i >= 0) {
tags.splice(i, 1);
console.log("post splice: " + tags);
$('select').val(tags).trigger('change.select2');
}
}
})
function ajaxPost(subject){
console.log("In ajaxPost");
var formData = {subject : subject}
$.ajax({
type : "POST",
contentType : "application/json",
url : "/api/subjects/save",
data : JSON.stringify(formData),
dataType : 'json'})
.done(console.log("Done posting " + JSON.stringify(formData)))
.fail(function(e) {
alert("Error!")
console.log("ERROR: ", e);
});
}
function addSubject(subjects, input) {
if (!input || input.length < 3) return false
var allSubjects = [];
$.each(subjects, function(i, subject){
if(subject.text) allSubjects.push(subject.text.toLowerCase())
});
console.log("Here is the entered subject: " + input);
if(allSubjects.includes(input)){
console.log(input + " already exists")
return true
}
if(confirm("Are you sure you want to add this new subject " + input + "?")){
console.log(input + " is going to be added to the database");
return true
}
console.log(input + " will NOT to added to the database");
return false
}
});
This works, but I would love to hear feedback on this approach!
本文标签: javascriptWrite new select2 option tags to local database in expressStack Overflow
版权声明:本文标题:javascript - Write new select2 option tags to local database in express - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742211871a2433859.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论