Я работаю над компонентом автозаполнения TypeScript (для Angular 2, хотя это не является ключевым вопросом), и я бы хотел управлять большинством (или всеми) его через наблюдаемые в RxJs (5,0,0-бета8). У меня возникают проблемы с отслеживанием позиции текущего элемента в списке предложений при действии с помощью клавиш со стрелками вверх/вниз: индекс остается застрявшим на 0.Отслеживать текущее положение в списке типов с наблюдаемыми
Вся следующая логика отложена в отдельном class
, который получает входные наблюдаемые и производит выходные наблюдаемые для подписки на них (поэтому не имеет строгого отношения к Angular 2). Клиентский код правильно подписывается на выходные наблюдаемые данные.
Вот код:
// Component responsible for managing only the list of suggestions
// It receives inputs from text field and it produces outputs
// as current index in list, when to hide list, etc.
class AutocompleteListDriver {
currentIndex$: Observable<number>;
doClose$: Observable<void>;
// ...
constructor(...
matches$: Observable<string[]>, // list of suggestions matching text in field
keyUp$: Observable<KeyboardEvent>, // keyup events from text field
keyDown$: Observable<KeyboardEvent>, // keydown events from text field
...) {
const safeMatches$ = matches$
.startWith([]); // start with a clear, known state internally
// when list is empty, component is hidden at rest:
// detect keys only when component is visible
const isActive$ = safeMatches$
.map(matches => matches.length !== 0);
const activeKeyUp$ = keyUp$
.withLatestFrom(isActive$)
.filter(tuple => tuple[1]) // -> isActive
.map(tuple => tuple[0]); // -> keyboardEvent
this.currentIndex$ = safeMatches$
.switchMap(matches => {
const length = matches.length;
console.log('length: ' + length);
const initialIndex = 0;
const arrowUpIndexChange$ = activeKeyUp$
.filter(isArrowUpKey)
.map(_ => -1);
const arrowDownIndexChange$ = activeKeyUp$
.filter(isArrowDownKey)
.map(_ => +1);
const arrowKeyIndexChange$ = Observable
.merge(arrowUpIndexChange$, arrowDownIndexChange$)
.do(value => console.log('arrow change: ' + value));
const arrowKeyIndex$ = arrowKeyIndexChange$
.scan((acc, change) => {
// always bound result between 0 and length - 1
const index = limitPositive(acc + change, length);
return index;
}, initialIndex)
.do(value => console.log('arrow key index: ' + value))
.startWith(0);
return arrowKeyIndex$;
})
.do(value => console.log('index: ' + value))
.share();
}
}
Идея заключается в том, что каждый раз, когда новый список ссылок (предложений) испускается, текущий индекс в списке должен начать новую «последовательность», так сказать. Каждая из этих последовательностей начинается с 0, прислушивается к приращениям/сокращениям из-за клавиш со стрелкой вниз/вверх, накапливает их, стараясь не выходить за пределы нижнего/верхнего предела.
Чтобы начать новую последовательность, это переводит на switchMap
. Но с таким кодом, только консоль показывает:
length: 5
index: 0
и не стрелка клавиши вверх/вниз не обнаружены на всех (пытался вставляя другие журналы на arrowDownIndexChange$
), так больше журналов и не оказывает влияния на конечного компонента. Это похоже на то, что их наблюдаемые не являются , а подписали, но, насколько я знаю, switchMap
должен подписаться на последнюю сгенерированную последовательность и отказаться от подписки на все предыдущие.
Просто, чтобы попробовать, я использовал mergeMap
: в этом случае обнаружены клавиши со стрелками, но, конечно, проблема в том, что все последовательности (из-за предыдущих моментов, когда совпадают с установленными) объединяются вместе, а их значения перекрываются друг с другом. Кроме того, в любом случае это неверно, время от времени список совпадений будет пустым, поэтому всегда есть точка, где текущая индексная последовательность всегда остается равной 0. Эта последовательность сливается и перекрывается со всеми остальными, давая чистый результат индекса, застрявшего в 0.
Что я делаю неправильно?
В любом случае вы можете сделать это в plunkr? Это облегчит отслеживание проблемы. – paulpdaniels
компонент вверх [на github] (https://github.com/BrainCrumbz/ng2-autocomplete-words-example/) с примером приложения. [Это] (https://github.com/BrainCrumbz/ng2-autocomplete-words-example/blob/ec42b926f04abea6a722673a7389363196fa36a5/src/client/autocomplete/acw-list-driver.ts#L82) вызов 'switch()' , Я понимаю, что это не то же самое, что плункер, но, возможно, в качестве первого шага это может помочь сыграть на нем? – superjos