#javascript #jquery #ajax #express #jquery-select2
#javascript #jquery #ajax #выразить #jquery-select2
Вопрос:
Я использую select2 в приложении Express для создания поля ввода, в котором пользователи могут выбирать объекты из списка, и могут обновлять этот список любыми недавно добавленными параметрами.
Проблема, с которой я борюсь, заключается в том, что select2
выполняется на стороне клиента, тогда как любые данные, которые я использую для заполнения своих <option>
тегов (к которым я хочу добавить новые параметры), находятся на стороне сервера.
Я хочу, чтобы пользователи могли добавлять темы, которых нет в исходном списке, чтобы будущим пользователям были представлены недавно добавленные опции (а также исходные)
Вот варианты, которые я рассмотрел для достижения этого (для повышения желательности):
- Добавьте новые
<option>Subject</option>
html-теги для каждого добавленного тега - Поместить новые теги в массив и заполнить
<option>
s из этого массива - Заполнять
<option>
изjson
объекта и обновлять этот объект при создании тега - Заполнять
<option>
из внешней базы данных (например, mongoose) и обновлять это при создании тега
Насколько я могу видеть, все эти опции требуют, чтобы мой клиентский код ( select2-js
) взаимодействовал с кодом на стороне сервера (где был бы мой массив, .json
файл или mongoose
схема), и я понятия не имею, как это сделать.
В моем текущем подходе я пытаюсь указать «локальный» json
файл в качестве источника данных в моем select2
вызове (смотрите здесь). Однако при этом база данных не заполняется никакими параметрами, так что это работает не так, как я ожидал.
Затем я проверяю, существует ли каждый новый тег в массиве ( dataBase
), и добавляю его в базу данных, если нет:
// 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
};
Однако этот подход добавит новые теги в массив, который будет уничтожен, как только я обновлю страницу, и новые теги не будут сохранены.
Как я могу изменить это, чтобы загружать данные на стороне сервера ( json
, mongoose
документ или что-либо еще, что считается наилучшей практикой), и обновлять эти данные новыми добавленными параметрами (которые проходят мои тесты)?
Комментарии:
1. Используйте ajax для заполнения json на странице. Затем используйте json для заполнения опции select2, как вы делаете в данный момент. Прикрепите json к document.ready и к обновлению базы данных, чтобы получить свой результат
2. @LelioFaieta — спасибо за указания. Есть ли шанс, что вы могли бы добавить это в качестве ответа?
Ответ №1:
На стороне вашего сервера у вас может быть api, который поддерживает и возвращает массив тегов. Если вы хотите, чтобы массив сохранялся даже после завершения работы сервера, вы можете сохранить массив тегов в базе данных.
На стороне сервера:
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});
} );
На стороне клиента:
$(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
};
Комментарии:
1. Спасибо. Я рассмотрю это сегодня вечером. Является
YOUR_SERVER_ADDRESS
относительным или абсолютным путем? Нужно ли мне вводить / запрашиватьajax
, чтобы это сработало?2. YOUR_SERVER_ADDRESS — это абсолютный адрес вашего веб-сервера, который обслуживает api. Если на вашем компьютере запущен локальный сервер, он должен быть localhost:PORT_NUMBER . Опять же, PORT_NUMBER зависит от сервера, на котором вы работаете. По умолчанию сервер узла работает на порту 3000. Для этого нужен jquery.
Ответ №2:
Для этого вы можете использовать select2:select
и select2:unselect
event.
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>
Ответ №3:
Вот что у меня получилось (благодаря обоим ответам):
1. Настройте базу данных Mongoose для хранения объектов:
models/subjects.js
var mongoose = require("mongoose");
var SubjectSchema = new mongoose.Schema({
subject: { type: String },
});
module.exports = mongoose.model("Subjects", SubjectSchema);
2. Настройте маршруты api в серверной части node js express:
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. Настройте select2
поле ввода:
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
}
});
Это работает, но я хотел бы услышать отзывы об этом подходе!