6
votes

Ecrire de nouvelles balises d'option select2 dans la base de données locale dans express

J'utilise select2 dans une application express pour créer une zone de saisie dans laquelle les utilisateurs peuvent sélectionner des sujets dans une liste, et peut mettre à jour cette liste avec toutes les options nouvellement ajoutées. Les balises (auxquelles je souhaite ajouter de nouvelles options) sont côté serveur.

Je veux que les utilisateurs puissent ajouter des sujets qui n'existent pas dans l'original liste, afin que les futurs utilisateurs se voient présenter les options nouvellement ajoutées (ainsi que les options d'origine)

Voici les options que j'ai envisagées pour y parvenir (en augmentant la désirabilité ):

  • Ajoutez de nouvelles balises html pour chaque balise ajoutée
  • Poussez de nouvelles balises dans un tableau et amorcez les à partir de ce tableau
  • Amorcez l ' à partir d'un objet json et mettez à jour cet objet lors de la création de balises
  • Semez le à partir d'une base de données externe (par exemple, la mangouste) et mettez-la à jour lors de la création de balises

Pour autant que je sache, toutes ces options nécessitent que mon code côté client ( select2-js ) parle au code côté serveur (où mon tableau, .json ou le schéma mongoose serait), et Je ne sais pas comment procéder .

Dans mon approche actuelle, j'essaie de spécifier un fichier json "local" comme source de données dans mon appel select2 ( voir ici ). Cependant, cela n'amorce pas la base de données avec des options, donc cela ne fonctionne pas comme prévu.

Je vérifie ensuite si chaque nouvelle balise existe dans un tableau ( dataBase ), et je l'ajoute à la base de données sinon:

// 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
};

Cependant, cette approche ajoutera les nouvelles balises à un tableau qui sera détruit une fois que j'actualiserai la page, et les nouvelles balises ne seront pas stockées.

Comment puis-je modifier cela pour charger le serveur- données secondaires ( json , document mangouste ou tout autre document considéré comme une bonne pratique), et mettre à jour ces données avec des options nouvellement ajoutées (qui réussissent mes tests)? strong >


2 commentaires

Utilisez ajax pour remplir le json sur la page. Ensuite, utilisez le json pour remplir le select2 comme vous le faites actuellement. Attachez le json à document.ready et à la mise à jour de la base de données pour obtenir votre résultat


@LelioFaieta - merci pour les pointeurs. Y a-t-il une chance que vous puissiez ajouter ceci comme réponse?


3 Réponses :


5
votes

Vous pouvez utiliser les événements select2: select et select2: unselect pour cela.

<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>
.select2-container {
  width: 200px;
}
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);
  });
});


0 commentaires

5
votes

Côté serveur, vous pouvez avoir une API qui gère et renvoie le tableau de balises. Si vous souhaitez que le tableau persiste même après l'arrêt du serveur, vous pouvez stocker le tableau de balises dans une base de données.

Côté serveur:

$(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
};

Côté client:

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});
} );


2 commentaires

Merci. Je vais examiner cela ce soir. YOUR_SERVER_ADDRESS est-il le chemin relatif ou absolu? Aurai-je besoin d'intall / requite ajax pour que cela fonctionne?


YOUR_SERVER_ADDRESS est l'adresse absolue de votre serveur Web qui sert l'API. Si vous exécutez un serveur local sur votre ordinateur, il doit être localhost: PORT_NUMBER . Encore une fois, PORT_NUMBER dépend du serveur que vous utilisez. Par défaut, le serveur de nœuds fonctionne sur le port 3000. Vous avez besoin de jquery pour que cela fonctionne.



0
votes

Voici ce que j'ai obtenu (grâce aux deux réponses):

1. Configurez une base de données Mongoose pour contenir des sujets:

models / subjects.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
    }

});

2. Configurer les routes API dans le backend 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. Configurer le champ de saisie select2 :
public/js/select2.js

var mongoose = require("mongoose");

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

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

Cela fonctionne, mais j'aimerais avoir des commentaires sur cette approche!

p >


0 commentaires