2017-10-25 15 views
0

입력 항목에 대한 간단한 자동 완성 기능을 구현하고 있습니다. 모든 것이 잘 작동합니다. 입력 스크립트를 중단 한 후 500ms가되면 AJAX가 호출하고 백엔드에서 제안을받습니다. 나는 또한 그들을 선택 아래에 보여줍니다.넉 아웃 자동 완성 구현

문제는 팝업의 가시성을 제어하는 ​​방법에 대한 아이디어가 없다는 것입니다. 입력 흐림시이를 숨길 때 입력을 포커스를 잃고 팝업이 즉시 숨겨지기 때문에 클릭 할 수조차 없습니다. 더 문제가되는 것은 Knockout의 foreach/template 콤보 내부에 팝업이 표시되므로 다중 뷰 모델에 의해 제어되는 여러 입력이 있다는 것입니다. 이렇게하면 jQuery를 사용하여 입력 + 팝업 영역 외부의 클릭을 더 세게 추적 할 수 있습니다.

<div class="form-group"> 
    <label>Name</label> 
    <div class="autocomplete-container" tabindex="0" data-bind="hasFocus: nameFocused"> 
     <input type="text" class="form-control" placeholder="Name" data-bind="textInput: name, event: { change: changed }"> 
     <select class="autocomplete" size="5" data-bind="visible: showSuggestions, options: ingredientSuggestions, optionsText: 'name', value: selectedSuggestion"></select> 
    </div>      
    <span class="label label-danger" data-bind="validationMessage: name"></span> 
</div> 

관련 JS, 항목의 뷰 모델의 일부 : I가 시도

var autocompleteTimer = null; 
var ingredientSuggestions = ko.observableArray(); 
var selectedSuggestion = ko.observable(); 
var nameFocused = ko.observable(); 
var suggestionsAvailable = ko.observable(false); 
var showSuggestions = ko.computed(() => nameFocused() && suggestionsAvailable()); 

(...) 

var suggestionsReceived = function(suggestions) { 

    var newSuggestions = new IngredientSuggestions(suggestions); 
    ingredientSuggestions(newSuggestions.suggestions); 

    suggestionsAvailable(ingredientSuggestions().length > 0); 
}; 

var requestSuggestions = function() { 

    autocompleteTimer = null; 

    recipeService.getIngredientSuggestions(name(), suggestionsReceived, null); 
}; 

var nameChanged = function (newValue) { 

    if (autocompleteTimer != null) { 
     clearTimeout(autocompleteTimer); 
    } 

    autocompleteTimer = setTimeout(requestSuggestions, 500); 
}; 

(실패 DIV의 초점을 추적하기위한 시도와)

HTML : 코드의

조각 입력 또는 팝업에 포커스가있을 때 팝업을 계속 표시합니다. 그러나 여전히 팝업을 클릭하려고하면 입력에 포커스가 "빠릅니다"가 사라지고 팝업 숨기기가 발생하여 아무런 클릭이나 포커스도 발생하지 않습니다.

숨기기 제안 팝업에 어떻게 접근해야합니까?

+0

내가 모든 제안을 몸에 클릭 이벤트 리스너를 추가하고 클릭 숨기기에있다. 그런 다음 자동 완성 입력 또는 추천 컨테이너에 클릭이 있었는지 확인하고 관련 제안을 표시합니다. – juvian

답변

0

내 조언은 showSuggestions에 세 개의 값을 결합하는 것입니다 :

  1. 어떤 제안이 있습니까
  2. 초점
  3. 의 검색 필드가 초점이 제안 선택 상자가되어

포커스를 전환하면 잠시 후에 이 표시되지 않습니다.에 포커스가 있습니다. 제안 상자를 숨기고 포커스를 허용하지 않습니다. 그래서 계산 된 가시성에서 약간의 시간 초과가 필요할 수 있습니다.

는 다음 동작을 보여줍니다 동작하는 예제입니다 :

const data = getData(); 
 

 
const query = ko.observable(""); 
 
const suggestions = ko.pureComputed(
 
() => query().length 
 
    ? data.filter(countryMatch(query().toUpperCase())) 
 
    : [] 
 
); 
 
    
 

 
const queryFocus = ko.observable(false) 
 
const selectFocus = ko.observable(false); 
 

 

 
const suggestionsAvailable = ko.pureComputed(
 
() => !!suggestions().length 
 
); 
 

 
// The relevant part: 
 
const showSuggestions = ko.pureComputed(
 
() => suggestionsAvailable() && 
 
     (queryFocus() || selectFocus()) 
 
).extend({ deferred: true, rateLimit: 100 }); 
 

 

 
ko.applyBindings({ query, queryFocus, selectFocus, suggestions }) 
 

 

 
function countryMatch(q) { 
 
    return c => [c.name, c.code] 
 
    .join(" ") 
 
    .toUpperCase() 
 
    .includes(q); 
 
}; 
 

 
function getData() { 
 
    return [{"name":"Afghanistan","code":"AF"},{"name":"Argentina","code":"AR"},{"name":"Belarus","code":"BY"},{"name":"Brazil","code":"BR"},{"name":"Cayman Islands","code":"KY"},{"name":"Congo, The Democratic Republic of the","code":"CD"},{"name":"Dominica","code":"DM"},{"name":"Faroe Islands","code":"FO"},{"name":"Germany","code":"DE"},{"name":"Guinea","code":"GN"},{"name":"India","code":"IN"},{"name":"Jersey","code":"JE"},{"name":"Latvia","code":"LV"},{"name":"Madagascar","code":"MG"},{"name":"Mayotte","code":"YT"},{"name":"Namibia","code":"NA"},{"name":"Niue","code":"NU"},{"name":"Paraguay","code":"PY"},{"name":"Russian Federation","code":"RU"},{"name":"Saudi Arabia","code":"SA"},{"name":"South Africa","code":"ZA"},{"name":"Syrian Arab Republic","code":"SY"},{"name":"Tunisia","code":"TN"},{"name":"United States Minor Outlying Islands","code":"UM"},{"name":"Yemen","code":"YE"}]; 
 
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script> 
 

 
<input type="search" data-bind="textInput: query, 
 
           hasFocus: queryFocus"/> 
 
<select size="5" data-bind="options: suggestions, 
 
          optionsText: 'name', 
 
          hasFocus: selectFocus, 
 
          visible: showSuggestions">