Lista rozwijana Select2, ale zezwolić na nowe wartości według użytkownika?

125

Chcę mieć listę rozwijaną z zestawem wartości, ale także pozwolić użytkownikowi „wybrać” nową wartość, której tam nie ma.

Widzę, że select2 obsługuje to, jeśli używasz go w tagstrybie, ale czy jest sposób, aby to zrobić bez używania tagów?

johnjohn
źródło
1
Select2 nigdy nie działało dla mnie, przynajmniej createSearchChoice nigdy nie działało dla mnie w 4.0.3 i nie chciałem, aby moi użytkownicy czekali na zakończenie AJAX, aby zwrócić to samo słowo kluczowe, więc musiałem wdrożyć własną bibliotekę, jestem tylko udostępnienie go, ponieważ myślę, że może to pomóc innym, którzy nadal są zdezorientowani tak jak ja, proszę nie głosować, jeśli nie zgadzasz się z moją odpowiedzią: github.com/razzbee/tagcomplete
razzbee.

Odpowiedzi:

100

W przypadku wersji 4+ sprawdź odpowiedź Kevina Browna poniżej

W Select2 3.5.2 i niższych możesz użyć czegoś takiego:

$(selector).select2({
  minimumInputLength:1,
  "ajax": {
    data:function (term, page) {
      return { term:term, page:page };
    },
    dataType:"json",
    quietMillis:100,
    results: function (data, page) {
      return {results: data.results};
    },
    "url": url
  },
  id: function(object) {
    return object.text;
  },
  //Allow manually entered text in drop down.
  createSearchChoice:function(term, data) {
    if ( $(data).filter( function() {
      return this.text.localeCompare(term)===0;
    }).length===0) {
      return {id:term, text:term};
    }
  },
});

(wzięte z odpowiedzi na liście mailingowej select2, ale nie mogę teraz znaleźć linku)

fmpwizard
źródło
4
Przepraszamy za spóźnioną odpowiedź, ale bardzo dziękuję za rozwiązanie! Drugi plakat zamieścił link do twojego sedna, co sprawia, że ​​jesteś podwójnie niesamowity! :)
johnjohn
rrauenza niesamowite, dokładnie to, czego szukałem
Matthias S
4
Dodanie selectOnBlur: truetestamentu wykona zadanie, zobacz: stackoverflow.com/questions/25616520/…
Alireza Fattahi
1
Tylko ostrzeżenie dla przyszłych czytelników, z których prawdopodobnie chcesz korzystać tags: []wraz z createSearchChoice.
Kevin Brown
5
Skrzypce połączone powyżej wydają się zepsute.
Wolfr
175

Doskonała odpowiedź udzielana przez @fmpwizard pracuje Select2 3.5.2 i poniżej, ale to nie będzie działać w 4.0.0 .

Od samego początku (ale być może nie tak wcześnie jak to pytanie) Select2 obsługuje „tagowanie”: gdzie użytkownicy mogą dodawać własne wartości, jeśli im na to pozwolisz. Można to włączyć za pomocą tagsopcji i można pobawić się przykładem w dokumentacji .

$("select").select2({
  tags: true
});

Domyślnie utworzy to opcję, która ma taki sam tekst, jak wpisane hasło wyszukiwania. Możesz zmodyfikować obiekt, który jest używany, jeśli chcesz oznaczyć go w specjalny sposób lub utworzyć obiekt zdalnie po jego wybraniu.

$("select").select2({
  tags: true,
  createTag: function (params) {
    return {
      id: params.term,
      text: params.term,
      newOption: true
    }
  }
});

Oprócz tego, że służy jako łatwa do wykrycia flaga na obiekcie przekazywanym przez select2:selectzdarzenie, dodatkowa właściwość umożliwia również nieco inne renderowanie opcji w wyniku. Więc jeśli chcesz wizualnie zasygnalizować fakt, że jest to nowa opcja, umieszczając obok niej „ (nowy) ”, możesz zrobić coś takiego.

$("select").select2({
  tags: true,
  createTag: function (params) {
    return {
      id: params.term,
      text: params.term,
      newOption: true
    }
  },
  templateResult: function (data) {
    var $result = $("<span></span>");

    $result.text(data.text);

    if (data.newOption) {
      $result.append(" <em>(new)</em>");
    }

    return $result;
  }
});
Kevin Brown
źródło
To było bardzo pomocne @ Markus1980Wien
abiieez
Myślę, że wielokrotnie użyłem tego fragmentu.
Sahu V Kumar
Jeśli nie działa, sprawdź, czy dodałeś tę opcję do select2, a nie dodawaj opcje Ajax. dla select2 ajax
Zohaib
2
Jego działanie w wersji select2 (4.0.6) wygląda następująco: $ ("select"). Select2 ({tags: true, createTag: function (params) {return {id: params.term, text: params.term, newOption : true}}, templateResult: function (data) {var result = data.text; if (data.newOption) {result = result + '(new)';} return result;}}); dzięki @Kevin Brown
M. Salah
To powinna być najlepsza odpowiedź. Szukałem tego od jakiegoś czasu, a ta opcja odpowiada na każde pytanie, które widziałem na ten temat.
Justin
14

Aby zachować kod, zamieszczam kod @rrauenza Fiddle z jego komentarza .

HTML

<input type='hidden' id='tags' style='width:300px'/>

jQuery

$("#tags").select2({
    createSearchChoice:function(term, data) { 
        if ($(data).filter(function() { 
            return this.text.localeCompare(term)===0; 
        }).length===0) 
        {return {id:term, text:term};} 
    },
    multiple: false,
    data: [{id: 0, text: 'story'},{id: 1, text: 'bug'},{id: 2, text: 'task'}]
});
Michel Ayres
źródło
2
Poszedłem na skrzypce, ale wygląda na to, że nie działa dla mnie w Chrome. Czy możesz potwierdzić?
IcedDante
@IcedDante kod działa. w skrzypcach chodzi tylko o to, żeby pokazać, jak należy to zrobić (selekcja jest ukryta w skrzypcach)
Michel Ayres
4
Kiedy idę na skrzypce, nigdzie nie widzę listy rozwijanej select2. Czy nie byłoby miło mieć przykład, który faktycznie… coś robi?
IcedDante
Jak mogę ustawić dane z zewnętrznego źródła? Chodzi mi o to, że chcę załadować miasta wybranego kraju, a sam wybrany kraj jest dropodownem?
Ali Baig
12

Ponieważ wiele z tych odpowiedzi nie działa w 4.0+, jeśli używasz Ajax, możesz poprosić serwer o dodanie nowej wartości jako opcji. Więc to działałoby tak:

  1. Użytkownik szuka wartości (co powoduje wysłanie żądania AJAX do serwera)
  2. Jeśli wartość jest duża, zwróć opcję. Jeśli nie, wystarczy, że serwer dołączy tę opcję w następujący sposób:[{"text":" my NEW option)","id":"0"}]
  3. Po przesłaniu formularza po prostu sprawdź, czy ta opcja jest w bazie danych, a jeśli nie, utwórz ją przed zapisaniem.
Eric
źródło
4

Poprawa w odpowiedzi @fmpwizard:

//Allow manually entered text in drop down.
createSearchChoice:function(term, data) {
  if ( $(data).filter( function() {
    return term.localeCompare(this.text)===0; //even if the this.text is undefined it works
  }).length===0) {
    return {id:term, text:term};
  }
},

//solution to this error: Uncaught TypeError: Cannot read property 'localeCompare' of undefined
Vikash Singh
źródło
Użyłem tego z niewielką modyfikacją, wstawię odpowiedź za chwilę, ale dzięki.
Sam
1
var text = 'New York Mills';
var term = 'new york mills';
return text.localeCompare(term)===0;

W większości przypadków musimy porównać wartości z niewrażliwym rejestrem. A ten kod zwróci false, co doprowadzi do utworzenia zduplikowanych rekordów w bazie danych. Ponadto metoda String.prototype.localeCompare () nie jest obsługiwana przez przeglądarkę Safary i ten kod nie będzie działał w tej przeglądarce;

return this.text.localeCompare(term)===0;

lepiej zastąpi

return this.text.toLowerCase() === term.toLowerCase();
prześcignąć
źródło
1

Dzięki za pomoc, użyłem poniższego kodu w Codeigniter II używam wersji: 3.5.2 programu select2.

var results = [];
var location_url = <?php echo json_encode(site_url('job/location')); ?>;
$('.location_select').select2({
    ajax: {
        url: location_url,
        dataType: 'json',
        quietMillis: 100,
        data: function (term) {
            return {
                term: term
            };
        },
        results: function (data) {
            results = [];
            $.each(data, function(index, item){
                results.push({
                    id: item.location_id,
                    text: item.location_name
                });
            });
            return {
                results: results
            };
        }
    },
    //Allow manually entered text in drop down.
    createSearchChoice:function(term, results) {
        if ($(results).filter( function() {
            return term.localeCompare(this.text)===0; 
        }).length===0) {
            return {id:term, text:term + ' [New]'};
        }
    },
});
Sam
źródło