jQuery select2: duplicate tag getting recreated
Asked Answered
S

3

1

I asked a question earlier today (jquery select2: error in getting data from php-mysql). However, I am trying to fix it and doing that now I am getting bit strange issue. I am not sure why it is happening like this.

Below is the JavaScript code.

<div class="form-group">
   <label class="col-sm-4 control-label">Product Name</label>
   <div class="col-sm-6">       
      <input type="hidden" id="tags" style="width: 300px"/>
   </div>
</div>

<script type="text/javascript">
var lastResults = [];

$("#tags").select2({
    multiple: true,
    placeholder: "Please enter tags",
    tokenSeparators: [","],
    initSelection : function (element, callback) {
        var data = [];
        $(element.val().split(",")).each(function () {
            data.push({id: this, text: this});
        });
        callback(data);
    },
    ajax: {
        multiple: true,
        url: "fetch.php",
        dataType: "json",
        type: "POST",
      data: function(term) {
                        return {q: term};
                    },
                    results: function(data) {
                        return {results: data};
                    }, 

    },
    createSearchChoice: function (term) {
        var text = term + (lastResults.some(function(r) { return r.text == term }) ? "" : " (new)");
        return { id: term, text: text };
    },
});

$('#tags').on("change", function(e){
    if (e.added) {
        if (/ \(new\)$/.test(e.added.text)) {
           var response = confirm("Do you want to add the new tag "+e.added.id+"?");
           if (response == true) {
              alert("Will now send new tag to server: " + e.added.id);
              /*
               $.ajax({
                   type: "POST",
                   url: '/someurl&action=addTag',
                   data: {id: e.added.id, action: add},    
                   error: function () {
                      alert("error");
                   }
                });
               */
           } else {
                console.log("Removing the tag");
                var selectedTags = $("#tags").select2("val");
                var index = selectedTags.indexOf(e.added.id);
                selectedTags.splice(index,1);
                if (selectedTags.length == 0) {
                    $("#tags").select2("val","");
                } else {
                    $("#tags").select2("val",selectedTags);
                }
           }
        }
    }
});
</script>

Here is the php code (fetch.php)

<?php 
// connect to database 
require('db.php');

// strip tags may not be the best method for your project to apply extra layer of security but fits needs for this tutorial 
$search = strip_tags(trim($_GET['q'])); 
//$search='te';
// Do Prepared Query 
$query = $mysqli->prepare("SELECT tid,tag FROM tag WHERE tag LIKE :search LIMIT 4");

// Add a wildcard search to the search variable
$query->execute(array(':search'=>"%".$search."%"));

// Do a quick fetchall on the results
$list = $query->fetchall(PDO::FETCH_ASSOC);

// Make sure we have a result
if(count($list) > 0){
   foreach ($list as $key => $value) {
    $data[] = array('id' => $value['tid'], 'text' => $value['tag']);                
   } 
} else {
   $data[] = array('id' => '0', 'text' => 'No Products Found');
}

// return the result in json
echo json_encode($data);

?>

select2 version is 3.5

Above code is able to send/receive request from database by using fetch.php.

Problem is in my database there are two records test & temp when I tag any one of them it create new tag.

It should work like this: if database have value then it won't create the new tag with same name.

enter image description here

Update

enter image description here

Smilax answered 5/2, 2016 at 19:1 Comment(0)
S
1

Finally it is working now. I would like to thanks @alex & @milz for their support. Here is the full n final code. Now duplicate tags are not creating. However, i am working to add tag in database.

php/html file

<div class="form-group">
   <label class="col-sm-4 control-label">Product Name</label>
   <div class="col-sm-6">
      <input type="hidden" id="tags" style="width: 300px"/>
   </div>
</div>

<script type="text/javascript">
var lastResults = [];

$("#tags").select2({
    multiple: true,
    tags: true,
    placeholder: "Please enter tags",
    tokenSeparators: [',', ' '],//[","],
    initSelection : function (element, callback) {
        var data = [];
        $(element.val().split(",")).each(function () {
            data.push({id: this, text: this});
        });
        callback(data);
    },
    ajax: {
        multiple: true,
        url: "fetch.php",
        dataType: 'json',
      //  type: "POST",
       data: function(term,page) {
                        return {
                            term: term
                           };
                    },
                    results: function(data,page) {
                         lastResults = data;                       
                          return {results: data};

                    }, 
    },
    maximumSelectionSize: 3,
    minimumInputLength: 3,
createSearchChoice: function(term) {
    console.log($(this).attr('data'));
    var text = term + (lastResults.some(function(r) {

     console.log(r.text);
      console.log(term);
      return r.text == term
    }) ? "" : " (new)");

    return {
      id: term,
      text: text
    };
  },
});

$('#tags').on("change", function(e){
    if (e.added) {
        if (/ \(new\)$/.test(e.added.text)) {

           var response = confirm("Do you want to add the new tag "+e.added.id+"?");
           if (response == true) {
              alert("Will now send new tag to server: " + e.added.id);
              /*
               $.ajax({
                   type: "POST",
                   url: '/someurl&action=addTag',
                   data: {id: e.added.id, action: add},    
                   error: function () {
                      alert("error");
                   }
                });
               */
           } else {
                console.log("Removing the tag");
                var selectedTags = $("#tags").select2("val");
                var index = selectedTags.indexOf(e.added.id);
                selectedTags.splice(index,1);
                if (selectedTags.length == 0) {
                    $("#tags").select2("val","");
                } else {
                    $("#tags").select2("val",selectedTags);
                }
           }
        }
    }
});
</script>

Here is the php file to get the data from database. fetch.php

<?php 
// connect to database 
require('db.php');

// strip tags may not be the best method for your project to apply extra layer of security but fits needs for this tutorial 
//if(isset($_GET)){
$search = strip_tags(trim($_GET['term'])); 

// Do Prepared Query 
$query = $mysqli->prepare("SELECT tid,tag FROM tag WHERE tag LIKE :search LIMIT 4");

// Add a wildcard search to the search variable
$query->execute(array(':search'=>"%".$search."%"));

$list = $query->fetchall(PDO::FETCH_ASSOC);

if(count($list) > 0){
   foreach ($list as $key => $value) {
    $data[] = array('id' => $value['tag'], 'text' => $value['tag']);            
   } 
} else {
   $data[] = array('id' => 'No Products Found', 'text' => 'No Products Found');
}

echo json_encode($data);

?>

It took lots of time. Almost 3 days. I hope it will save someone efforts.

Smilax answered 7/2, 2016 at 18:38 Comment(0)
G
2

Tags need an id and a text. The issue you're facing is that your text doesn't match the id.

So, even if you write the same text, Select2 thinks the new text is a new option because the id don't match.

To solve your issue, you need to set the id with the same value as the text. Change the foreach of your fetch.php to the following:

foreach ($list as $key => $value) {
    $data[] = array('id' => $value['tag'], 'text' => $value['tag']);                
} 

Update: You also need to update the variable lastResults to avoid the duplication of tags with the same text. When you bind select2, you need to change the results property of ajax to this (based on this answer:

ajax: {
    multiple: true,
    url: "fetch.php",
    dataType: "json",
    type: "POST",
    data: function(term) {
        return {q: term};
    },
    results: function(data) {
        lastResults = data.results;
        return {results: data};
    }, 
},

Note the lastResults = data.results;. Without this, the lastResults variable is always empty and, when the createSearchChoice function is executed, it will always return a new tag.

Gettysburg answered 6/2, 2016 at 18:23 Comment(10)
Thanks for your help. I will check and let you know.Smilax
Now there is another issue. If i am writing test in the search box then it is showing me test there but it create a new tag like this test (new tag). i am attaching screenshot.Smilax
one more thing if i use comma (,) then it is creating duplicate tag. if i use tab or enter then it won'tSmilax
@404 I've created a demo with static data (the temp and test) so you can see how it's working. As for the creation of tags through enter, tab or comma, it's working on my fiddle. I guess you should try to make it work with static data first and then connect select2 to PHP and MySQL. Check the fiddle here: jsfiddle.net/milz/avqfjc33Nonmoral
i checked your fiddle and it also had same issue as mine. try to enter test in search box and after that press comma you will see test new will get created.Smilax
@404: Yes, I see that. It seems that you took part of this answer's code but remove a important part of it. On the createSearchChoice, you're using lastResults, but this value is always empty. Take a look at the answer were you took the code and check the usage of lastResults on the results of ajax. I updated my fiddle to assume the options and it's working correctly (jsfiddle.net/milz/avqfjc33/1)Nonmoral
Thanks for your detailed explanation. However, i didn't figure out how to use lastresults. i didn't copied from there but somewhere else. data: function(term,page) { return { term: term }; }, results: function(data,page) { lastResults = data.results; return data; },Smilax
Thanks for your support. It didn't helped. i tried as you suggested but it is not showing data from database. I can see data is coming from db but it is not showing. Uncaught TypeError: Cannot read property 'some' of undefined. $.select2.createSearchChoice @ tag.php:84(anonymous function)Smilax
Let us continue this discussion in chat.Smilax
Finally it is working. now i am working on adding tag in database.Smilax
S
1

Finally it is working now. I would like to thanks @alex & @milz for their support. Here is the full n final code. Now duplicate tags are not creating. However, i am working to add tag in database.

php/html file

<div class="form-group">
   <label class="col-sm-4 control-label">Product Name</label>
   <div class="col-sm-6">
      <input type="hidden" id="tags" style="width: 300px"/>
   </div>
</div>

<script type="text/javascript">
var lastResults = [];

$("#tags").select2({
    multiple: true,
    tags: true,
    placeholder: "Please enter tags",
    tokenSeparators: [',', ' '],//[","],
    initSelection : function (element, callback) {
        var data = [];
        $(element.val().split(",")).each(function () {
            data.push({id: this, text: this});
        });
        callback(data);
    },
    ajax: {
        multiple: true,
        url: "fetch.php",
        dataType: 'json',
      //  type: "POST",
       data: function(term,page) {
                        return {
                            term: term
                           };
                    },
                    results: function(data,page) {
                         lastResults = data;                       
                          return {results: data};

                    }, 
    },
    maximumSelectionSize: 3,
    minimumInputLength: 3,
createSearchChoice: function(term) {
    console.log($(this).attr('data'));
    var text = term + (lastResults.some(function(r) {

     console.log(r.text);
      console.log(term);
      return r.text == term
    }) ? "" : " (new)");

    return {
      id: term,
      text: text
    };
  },
});

$('#tags').on("change", function(e){
    if (e.added) {
        if (/ \(new\)$/.test(e.added.text)) {

           var response = confirm("Do you want to add the new tag "+e.added.id+"?");
           if (response == true) {
              alert("Will now send new tag to server: " + e.added.id);
              /*
               $.ajax({
                   type: "POST",
                   url: '/someurl&action=addTag',
                   data: {id: e.added.id, action: add},    
                   error: function () {
                      alert("error");
                   }
                });
               */
           } else {
                console.log("Removing the tag");
                var selectedTags = $("#tags").select2("val");
                var index = selectedTags.indexOf(e.added.id);
                selectedTags.splice(index,1);
                if (selectedTags.length == 0) {
                    $("#tags").select2("val","");
                } else {
                    $("#tags").select2("val",selectedTags);
                }
           }
        }
    }
});
</script>

Here is the php file to get the data from database. fetch.php

<?php 
// connect to database 
require('db.php');

// strip tags may not be the best method for your project to apply extra layer of security but fits needs for this tutorial 
//if(isset($_GET)){
$search = strip_tags(trim($_GET['term'])); 

// Do Prepared Query 
$query = $mysqli->prepare("SELECT tid,tag FROM tag WHERE tag LIKE :search LIMIT 4");

// Add a wildcard search to the search variable
$query->execute(array(':search'=>"%".$search."%"));

$list = $query->fetchall(PDO::FETCH_ASSOC);

if(count($list) > 0){
   foreach ($list as $key => $value) {
    $data[] = array('id' => $value['tag'], 'text' => $value['tag']);            
   } 
} else {
   $data[] = array('id' => 'No Products Found', 'text' => 'No Products Found');
}

echo json_encode($data);

?>

It took lots of time. Almost 3 days. I hope it will save someone efforts.

Smilax answered 7/2, 2016 at 18:38 Comment(0)
H
0

Apply the changes as in the select2.min.js (v4.0.6-rc.1) code snippet below

section 1

c.on("results:select", function() {
                    var a = e.getHighlightedResults();
                    if (0 !== a.length) {
                        var c = b.GetData(a[0], "data");
                        "true" == a.attr("aria-selected") ? e.trigger("close", {}) : e.trigger("select", {

                        //custom select2 tagging
                        if(a.attr("aria-selected")){
                            c.id = c.id + 1;
                        }
                        e.trigger("select", {
                            data: c
                        })

                        //"true" == a.attr("aria-selected") ? e.trigger("close", {}) : e.trigger("select", {
                        // e.trigger("select", {
                        //     data: c
                        // })

                    }
                })

section 2

this.on("query", function(b) {
                    a.isOpen() || a.trigger("open", {}), this.dataAdapter.query(b, function(c) {
                        //custom select2 tagging
                        let searchInput = $(".select2-search__field").val();
                        searchInput = {results: [{id: searchInput, text: searchInput}]};
                        a.trigger("results:all", {
                            data: c,
                            data: searchInput,
                            query: b
                        })
                    })
                })
Hibbitts answered 27/7, 2021 at 7:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.