Как предотвратить дублирование с помощью Bootstrap Tokenfield при использовании автозаполнения jQuery Ui

Я пытаюсь реализовать Bootstrap Tokenfield с автозаполнением jQuery Ui и до сих пор я смог это сделать, за исключением того, что я не могу предотвратить дубликаты в поле ввода, поэтому, к сожалению, мой пользователь может выбрать одно и то же значение дважды.

в моем поиске я обнаружил, что Bootstrap Tokenfield имеет способ предотвращение дублирования. Однако я не знаю, как применить к моему коду, потому что мне кажется, что он идет с Twitter typeahead и не jQuery Ui.

Как я могу предотвратить дублирование с помощью Bootstrap TokenField с помощью автозаполнения jQuery Ui ?

Это мой загрузочный код TokenField на основе автозаполнения jQuery ui

$('.tokenfield').tokenfield({
  autocomplete: {
    source: [
    {
        "id": "1",
        "value": "Ferdine Faithfull" 
    },
    {
        "id": "2",
        "value": "John Carta" 
    },
    {
        "id": "3",
        "value": "Mezane Smith" 
    }
    ],

    delay: 100
  },
  showAutocompleteOnFocus: true
});

и ниже то, что я нашел на Github, чтобы предотвратить дублирование, хотя я думаю, что это для Typeahead

$('#my-tokenfield').on('tokenfield:createtoken', function (event) {
    var existingTokens = $(this).tokenfield('getTokens');
    $.each(existingTokens, function(index, token) {
        if (token.value === event.attrs.value)
            event.preventDefault();
    });
});

4 ответов


Я думаю, что вы сделали все это, все, что вам остается сделать, это заменить класс

поэтому после первого кода вместо второго кода напишите

$('.tokenfield').on('tokenfield:createtoken', function (event) {
    var existingTokens = $(this).tokenfield('getTokens');
    $.each(existingTokens, function(index, token) {
        if (token.value === event.attrs.value)
            event.preventDefault();
    });
});

разница вот ваш класс, который должен быть применен, и он работает как для Twitter Typeahead и jQuery Ui


это предотвращает перечисление элементов, которые уже были добавлены в качестве токенов:

    $('.tokenfield').on('tokenfield:createdtoken tokenfield:removedtoken', function (event) {
    var field = $(this);
    var currentTokens = field.tokenfield('getTokens');
    var originalSource = field.data('bs.tokenfield').options.autocomplete.source;
    var newSource = originalSource.slice(); //clone original autocomplete source
    for (var i = newSource.length - 1; i >= 0; i--) {
      for (var j = currentTokens.length - 1; j >= 0; j--) {
        if (JSON.stringify(currentTokens[j].label) == JSON.stringify(newSource[i]) 
          || JSON.stringify(currentTokens[j]) == JSON.stringify(newSource[i]) ) {
          //remove the token from the newSource
          var index = newSource.indexOf(newSource[i]);
          if (index > -1) 
            newSource.splice(index, 1);
        };
      };
    };
    //update source
    field.data('bs.tokenfield').$input.autocomplete({source: newSource})
})

эта функция вызывается после создания или удаления маркера для обновления списка. Он использует JSON.stringify () для сравнения объектов и выполняет сравнение для строковых объектов и для {value: "foo", label: "bar"} исходных объектов.


@Javier ваше решение работает хорошо, но иногда он становится багги и добавить в два раза токен! У тебя есть идея для такого поведения?

PS после просмотра документации я нашел решение. Необходима обработка обоих событий. Потому что события запускаются до и после создания/редактирования / удаления токенов.

поэтому вам нужно это, чтобы предотвратить добавление (перед созданием события)

$('#tokenfield').on('tokenfield:createtoken', function (event) {
    var existingTokens = $(this).tokenfield('getTokens');
    //check the capitalized version
    event.attrs.value =  capitalizeFirstLetter(event.attrs.value);
    $.each(existingTokens, function(index, token) {
        if (token.value === event.attrs.value) {
            event.preventDefault();
            return false;
        }
    });
});

и этот другой тоже, как вы предложили, для исходного списка (после создания событие)

$('#tokenfield').on('tokenfield:createdtoken tokenfield:removedtoken', function (event) {
    var field = $(this);
    var currentTokens = field.tokenfield('getTokens').map(function(i){return i.value});
    var originalSource = field.data('bs.tokenfield').options.autocomplete.source;
    var newSource = [];
    for (var i = 0; i<originalSource.length; i++) {
      if(currentTokens.indexOf(originalSource[i])==-1){
        newSource.push(originalSource[i]);
      }
    };
    //update source
    field.data('bs.tokenfield').$input.autocomplete({source: newSource});
    //empty the input field
    $(".tokenfield.form-control").find("input.token-input").val("");
});

примечание: Я изменил " цикл проверки "(double for был переполнен) и добавил чек, чтобы избежать" капитализированного " соответствия, на всякий случай, если вам это нужно.

function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
}

$('.tokenfield').on('tokenfield:createtoken', function (event) {
    var existingTokens = $(this).tokenfield('getTokens');
    $.each(existingTokens, function(index, token) {
        if (token.value === event.attrs.value)
            event.preventDefault();
    });
});