2015-11-03 22 views
6

Pobieranie identyfikatorów i nazw użytkowników za pośrednictwem AJAX i używanie Select2 do ich wyszukiwania, ale moi użytkownicy poprosili o możliwość wyboru z menu rozwijanego przy użyciu klawisza Tab, traktując to jak naciśnięcie Enter. Oto moja deklaracja select2:Select2 4.0.0 AJAX - Wybierz wyróżnioną opcję za pomocą Tab

$("#user-select").select2({ 
    ajax: { 
     url: "/api/User", 
     method: "get", 
     data: function (params) { 
      return { 
       search: params.term 
      }; 
     }, 
     beforeSend: function() { 
      $(".loading-results").text("Loading..."); 
     }, 
     processResults: function (data) { 
      return { 
       results: data 
      }; 
     }, 
     cache: true 
    }, 
    allowClear: true, 
    placeholder: "Enter a User ID or Name", 
    templateResult: function (data) { 
     return "(" + data.id + ") " + data.name; 
    }, 
    templateSelection: function (data) { 
     return "(" + data.id + ") " + data.name; 
    } 

„.select2-search__field” wydaje się być skupiony elementem ilekroć widoczne, a element podświetlony rozwijanej dostaje klasę «select2-results__option - podkreślił.»

Próbowałem już kilku rozwiązań, ale nic nie zadziałało, szczególnie dlatego, że ten element pojawia się i znika w dowolnym momencie, gdy otwiera się rozwijane menu. Niestety, straciłem kod z moich prób, ale polegał głównie na wykonaniu preventDefault, kiedy Tab został trafiony na aktywnym wejściu, a następnie wywołaniu zdarzenia kliknięcia na podświetlonym elemencie lub wywołaniu klawisza Enter na wejściu.

Próbowałem także dostosować opcję selectOnClose, ale generalnie wydawało mi się to błędne i spowodowało nieskończoną pętlę, gdy miałem ją uruchomioną normalnie, znacznie mniej próbując ją przesłonić w oparciu o naciśnięty klawisz.

[Edycja]
Wybrane rozwiązanie działa, ale nie stanowią dla templateResult określonej zamiast wykazujące „() nieokreślone”. Tak więc, zmodyfikowałem go, aby dodać wyróżnioną odpowiedź jako wybraną opcję dla overlying Select, a następnie wywołaj zdarzenie change bezpośrednio w tym Select.

... (tak samo jak początkowej Select2)

}).on('select2:close', function (evt) { 
    var context = $(evt.target); 

    $(document).on('keydown.select2', function (e) { 
     if (e.which === 9) { // tab 
      var highlighted = context.data('select2').$dropdown.find('.select2-results__option--highlighted'); 

      if (highlighted) { 
       var data = highlighted.data('data'); 

       var id = data.id; 
       var display = data.name; 

       $("#user-select").html("<option value='" + id + "' selected='selected'>" + display + "</option>"); 
       $("#user-select").change(); 
      } 
      else { 
       context.val("").change(); 
      } 
     } 
    }); 
+0

czy już to wymyśliłeś? W tych samych problemach. – grant

+0

Nie ma kości, już wyczerpałem większość moich możliwości rozwiązywania problemów, zanim opublikowałem tutaj. Jeśli wiesz cokolwiek innego, powinienem oznaczyć to tagiem, aby pomóc ludziom znaleźć odpowiedź, daj mi znać, a ja to zmienię w poście. – MikeOShay

+1

Doceniam to - spędziłem trochę czasu waląc w to również bez powodzenia. Dam ci znać, jeśli coś wymyślę :) – grant

Odpowiedz

9

Próbowałem znaleźć rozwiązanie tego problemu, jak również.
Głównym problemem jest to, że zdarzenia select2 nie dają żadnego wglądu w to, który klawisz został naciśnięty.

Więc wymyśliłem ten hack, aby uzyskać dostęp do zdarzenia keydown w kontekście select2.
Testowałem to najlepiej jak potrafiłem i wygląda na to, że działa idealnie.

selectElement 
.select2({ options ... }) 
.on('select2:close', function(evt) { 
    var context = $(evt.target); 

    $(document).on('keydown.select2', function(e) { 
     if (e.which === 9) { // tab 
      var highlighted = context 
           .data('select2') 
           .$dropdown 
           .find('.select2-results__option--highlighted'); 
      if (highlighted) { 
       var id = highlighted.data('data').id; 
       context.val(id).trigger('change'); 
      } 
     } 
    }); 

    // unbind the event again to avoid binding multiple times 
    setTimeout(function() { 
     $(document).off('keydown.select2'); 
    }, 1); 
}); 
+0

Sprytnie! Nadal wychwytywania zdarzenia keydown podczas zdarzenia zamknięcia, a następnie ustawić go programowo. Nadal musisz ręcznie ustawić wartość wyników szablonu, jeśli jesteś szablonem. Przyjmę twoje i zaktualizuję pytanie, aby pokazać moje modyfikacje. – MikeOShay

+0

Tak, to jest hacky jak cholera, ale działa na razie :) – Sniffdk

+0

OOF, który jest brzydki, ale nadal wydaje się być najlepszą opcją (cholernie, jeśli wiem lepiej). Dzięki wielkie. – neanderslob

2

Dla każdego, kto chce dostać kartę-select pracę z multi-select, to pracował dla mnie:

$("#selected_ids").select2({ multiple: true }).on('select2:open', function(e) { selectOnTab(e) }); 

function selectOnTab(event){ 

    var $selected_id_field = $(event.target); 

    $(".select2-search__field").on('keydown', function (e) { 
    if (e.which === 9) { 
     var highlighted = $('.select2-results__option--highlighted'); 

     if (highlighted) { 
     var data = highlighted.data('data'); 
     var vals = $selected_id_field.val(); 
     if (vals === null){ 
      vals = []; 
     } 
     vals.push(data.id) 
     $selected_id_field.val(vals).trigger("change") 
     } 
    } 
    }); 
} 

Obecnie ogranicza mnie do jednego pola na stronie, ale to robi pracę.

Dziękuję Mikeoshay i Sniffdk za wkopanie się w to.
Obecnie nie jest kwestią otwartą, która może rozwiązać ten problem dla nas:

https://github.com/select2/select2/issues/3359

+1

Dzięki za rozwiązanie. Po prostu uwaga dla innych, wywołanie 'trigger (" change ")' nie spowoduje wystrzelenia zdarzeń DOM ('select2: open',' select2: close', etc) zwykle widzianych przy wyborze opcji. – Marklar

+0

Widzę pewne niepewne zachowanie keydown, gdzie czasami jest ono wywoływane pięć razy po naciśnięciu klawisza, czasem wcale. Czy masz pojęcie, co jest nie tak? – mmking

+0

@mmking Anegdotycznie i odnoszenie się do takich dyskusji jak [this] (https://stackoverflow.com/questions/9098168/jquery-keypress-event-fires-repeatedly-when-key-is-held-but-noton-on- all-keys) Wierzę, że to normalne zachowanie dla zdarzenia keydown. –

7

Funkcja selectOnClose wydaje się być stabilny w 4.0.3, a znacznie prostsze rozwiązanie:

$("#user-select").select2({ 
    ... 
    selectOnClose: true 
}); 

To możliwe że użycie szablonów przeszkadza tej funkcji, nie używam szablonów, więc tego nie przetestowałem.

+0

z selectOnClose, opcja jest wybrana, nawet jeśli klikniesz gdzie indziej w treści strony (nie klikając opcji w zaznaczeniu). Jeśli to był problem dla ciebie, czy byłeś w stanie znaleźć sposób na jego obejście? – Marklar

+0

W moim przypadku to nie był problem, więc nie szukałem sposobu obejścia tego. Domyślam się, że musiałbyś użyć rozwiązania @Sniffdk, aby odpowiedzieć tylko na TAB, ale nie na inne sposoby zamknięcia selekcji. –

+0

Dzięki za poświęcenie czasu na odpowiedź. Dla każdego innego w tej samej sytuacji rozwiązanie Sniffdk nie działa w przypadku wielokrotnego wyboru. Rozwiązanie JP ma, ale zwykłe zdarzenia DOM nie są uruchamiane. – Marklar

0

można po prostu zmienić źródło kontroli Select2, tylko jedną linię:

else if (key === KEYS.ENTER)

else if (key === KEYS.ENTER | | klucz === KEYS.TAB)

Z tego:

this.on('keypress', function (evt) { 
    var key = evt.which; 

    if (self.isOpen()) { 
    if (key === KEYS.ESC || key === KEYS.TAB || 
     (key === KEYS.UP && evt.altKey)) { 
     self.close(); 

     evt.preventDefault(); 
    } else if (key === KEYS.ENTER) { 
     self.trigger('results:select', {}); 

     evt.preventDefault(); 

W tym

this.on('keypress', function (evt) { 
    var key = evt.which; 

    if (self.isOpen()) { 
    if (key === KEYS.ESC || (key === KEYS.UP && evt.altKey)) { 
     self.close(); 

     evt.preventDefault(); 
    } else if (key === KEYS.ENTER || key === KEYS.TAB) { 
     self.trigger('results:select', {}); 

     evt.preventDefault(); 

zmianę można zrobić w pliku źródłowym src/js/select2/core.js lub w wersji skompilowanej. Kiedy stosowałem tę zmianę, zmodyfikowałem src/js/select2/core.js i wykonałem gruntfile.js, aby ponownie skompilować bibliotekę select2. To rozwiązanie nie jest obejściem, ale przyjemną funkcją dla select2.

+0

Sądzę, że to rozwiązanie zostało przesłane jako żądanie pobrania, ale opiekun select2 powiedział, że był to przełomowy i nie został scalony: https://github.com/select2/select2/pull/4325#issuecomment-229234605 – Marklar

+0

@Marklar , wszystkie testy i wszystko wydaje się dobrze z tą zmianą, nie ma żadnego problemu. Nie wiem, kto to nazwał "przełomową zmianą" i dlaczego. Do tej pory korzystałem z proponowanego rozwiązania bez problemu. –

+0

Dziękujemy za poświęcenie czasu na udzielenie odpowiedzi i dostarczenie rozwiązania. Sądzę, że być może zmiana jest czymś, o czym należy pamiętać, jeśli napotkasz jakiekolwiek niewyjaśnione problemy. Jeśli spojrzysz na link podany w moim ostatnim komentarzu, zobaczysz, że Kevin Brown (opiekun select2) stwierdził, że była to zmiana zerwania i że selectOnClose było jego rekomendacją. – Marklar

0

Po zabawie z tymi wszystkimi rozwiązaniami, ten wydaje się łapać większość przypadków i pracować najlepiej dla mnie. Uwaga Używam select2 4.0.3, ale nie podoba mi się selectOnClose, jeśli masz wiele pól select2 z wieloma może siać spustoszenie!

var fixSelect2MissingTab = function (event) { 
    var $selected_id_field = $(event.target); 

    var selectHighlighted = function (e) { 
     if (e.which === 9) { 
      var highlighted = $selected_id_field.data('select2').$dropdown.find('.select2-results__option--highlighted'); 

      if (highlighted) { 
       var data = highlighted.data('data'); 
       if (data) { 
        var vals = $selected_id_field.val(); 
        if (vals === null) { 
         vals = []; 
        } 
        if (vals.constructor === Array) { 
         vals.push(data.id); 
        } else { 
         vals = data.id; 
        } 
        $selected_id_field.val(vals).trigger("change"); 
       } 
      } 
     } 
    }; 

    $('.select2-search__field').on('keydown', selectHighlighted);  
} 

$(document).on('select2:open', 'select', function (e) { fixSelect2MissingTab(e) }); 
$(document).on('select2:close', 'select', function (e) { 
    //unbind to prevent multiple 
    setTimeout(function() { 
     $('.select2-search__field').off('keydown'); 
    }, 10); 
}); 

Zaletą tego rozwiązania jest jego ogólna charakterystyka i można go zastosować w kodzie źródłowym, który będzie działał nawet w przypadku dynamicznie dodawanych pól wyboru2.