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

Posted

技术标签:

【中文标题】在 express 中将新的 select2 选项标签写入本地数据库【英文标题】:Write new select2 option tags to local database in express 【发布时间】:2019-08-06 20:36:14 【问题描述】:

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

我正在努力解决的问题是 select2 在客户端运行,而我用来播种 <option> 标记(我想附加新选项)的任何数据都是在服务器端。

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

这些是我为实现这一目标而考虑过的选项(增加可取性):

为每个添加的标签添加新的<option>Subject</option> html 标签 将新标签推送到数组,并从该数组中播种<option>s 从json 对象中播种<option>,并在创建标签时更新此对象 从外部数据库(例如猫鼬)中播种 <option>,并在创建标签时更新它

据我所见,所有这些选项都要求我的客户端代码 (select2-js) 与服务器端代码(我的数组、.json 文件或 mongoose 架构所在的位置)对话, 我不知道该怎么做

在我目前的方法中,我试图在我的select2 调用 (see here) 中指定一个“本地”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 文档或其他任何被认为是最佳实践的内容),并使用新添加的选项更新此数据(通过我的测试)?

【问题讨论】:

使用 ajax 填充页面上的 json。然后像您当前所做的那样使用 json 填充 select2 。将 json 附加到 document.ready 和数据库更新以获取结果 @LelioFaieta - 感谢您的指点。你有机会把这个作为答案吗? 【参考方案1】:

您可以为此使用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>

【讨论】:

【参考方案2】:

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

服务器端:

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
;

【讨论】:

谢谢。我今晚会调查这个。 YOUR_SERVER_ADDRESS 是相对路径还是绝对路径?我是否需要安装/requite ajax 才能使其正常工作? YOUR_SERVER_ADDRESS 是为 api 提供服务的 Web 服务器的绝对地址。如果你在你的机器上运行一个本地服务器,它应该是localhost:PORT_NUMBER。再次,PORT_NUMBER 取决于您正在运行的服务器。默认情况下,节点服务器在端口 3000 上运行。您需要 jquery 才能工作。【参考方案3】:

这是我最终得到的结果(感谢两个答案):

1.设置 Mongoose DB 来保存主题:

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
    

);

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

【讨论】:

以上是关于在 express 中将新的 select2 选项标签写入本地数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Select2 中将参数附加到 ajax 请求?

使用格式动态设置 select2 选项

删除 Select2 Jquery 插件中的默认选择

保留 InitSelection -Select2

如何在 PixelAdmin 模板中将 select2 依赖插件更新到版本 4.0.6

如何在 Expression Blend 中将控件类型从按钮更改为切换按钮?