在 express 中将新的 select2 选项标签写入本地数据库

Write new select2 option tags to local database in express

我在 Express 应用程序中使用 select2 创建一个输入框,用户可以在其中 select 列表中的主题, 并且可以使用任何新添加的选项更新此列表.

我遇到的问题是 select2 在客户端运行,而我用来播种 <option> 标签(我想向其添加新选项)的任何数据都是服务器-side.

我希望用户能够添加原始列表中不存在的主题,以便将来的用户看到新添加的选项(以及原始选项)

这些是我考虑过的用于实现此目的的选项(越来越受欢迎):

据我所知,所有这些选项都需要我的客户端代码 (select2-js) 与服务器端代码(我的数组、.json 文件或 mongoose 模式),我不知道如何去做这个

在我目前的方法中,我试图在我的 select2 调用 (see here) 中指定一个 "local" json 文件作为我的数据源。但是,这不会为数据库提供任何选项,因此它没有像我预期的那样工作。

然后我检查数组中是否存在每个新标签 (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
};

但是,这种方法会将新标签添加到一个数组中,一旦我刷新页面,该数组就会被销毁,并且不会存储新标签。

我如何修改它以加载服务器端数据(jsonmongoose 文档或任何其他被认为是最佳实践的数据),并使用更新此数据新添加的选项(通过我的测试)?

您可以为此使用 select2:selectselect2:unselect 事件。

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>

在您的服务器端,您可以有一个 api 维护和 returns 标签数组。 如果您希望数组在服务器关闭后仍然存在,您可以将标签数组存储在数据库中。

服务器端:

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.设置一个 Mongoose 数据库来保存主题:

models/subjects.js

var mongoose = require("mongoose");

var SubjectSchema = new mongoose.Schema({
    subject: { type: String },
});

module.exports = mongoose.model("Subjects", SubjectSchema);

2。在 node js express 后端设置 api 路由:
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
    }

});

这可行,但我很想听听对此方法的反馈!