Skip to content

Instantly share code, notes, and snippets.

@thomhos
Last active October 19, 2016 15:35
Show Gist options
  • Save thomhos/540ff12ebf81426f87b7088a387aab65 to your computer and use it in GitHub Desktop.
Save thomhos/540ff12ebf81426f87b7088a387aab65 to your computer and use it in GitHub Desktop.
Autocomplete with RxJS
// Require libs
var Rx = require('rxjs/Rx');
var yo = require('yo-yo');
// Select dom elements
var inputField = document.querySelector('.input');
var suggestionsEl = document.querySelector('.suggestions');
// Create streams
var response$ = new Rx.BehaviorSubject({ query: '', results: []});
var selected$ = new Rx.BehaviorSubject(-1);
var input$ = Rx.Observable.fromEvent(inputField, 'keyup')
.share();
var query$ = input$
.throttleTime(200)
.filter(e => e.keyCode !== 38 && e.keyCode !== 40)
.map(e => e.target.value)
.distinctUntilChanged()
var request$ = query$
.filter(e => e.length > 3)
.map(e => ( /* do ajaxRequest => */ { query: e, results: [e, e+e, e+e+e] }))
.subscribe(response$);
var inputUpDown$ = input$
.filter(e => e.keyCode === 38 || e.keyCode === 40)
.map(e => (e.keyCode === 38 ? -1 : 1)).scan((acc, currentValue) => {
var nextValue = acc + currentValue; // acc is the state (selected$) and the input modifier is added to this
var response = response$.getValue().results; // this is the current state of the responses
nextValue = (nextValue < response.length ? nextValue : -1);
nextValue = (nextValue > -2 ? nextValue : response.length - 1);
return nextValue;
}, selected$.getValue())
.subscribe(selected$)
var inputClose$ = input$
.filter(e => e.keyCode === 27 || e.target.value.length == 0)
// Constuctor to create list element
listFunc = (res, selected) => yo`
<ul>
${ res.results.map((item, index) => yo`
<li>
<a href="#" class="${index == selected ? 'selected' : ''}">
<strong>${item.substring(0, res.query.length)}</strong>${item.substring(res.query.length)}
</a>
</li>`
)}
</ul>
`;
// Variables for list element
var list = listFunc(response$.getValue(), selected$.getValue());
// connect list to DOM
suggestionsEl.appendChild(list);
// Update list upon response
response$.subscribe(res => {
yo.update(list, listFunc(res, selected$.getValue()));
})
// Set index upon arrow keys
selected$.subscribe(e => {
yo.update(list, listFunc(response$.getValue(), e));
if(response$.getValue()[e]) {
inputField.value = response$.getValue()[e];
}
});
// Set index upon arrow keys
inputClose$.subscribe(closeDropdown);
function closeDropdown() {
response$.next({ query: '', results: []})
selected$.next(-1)
yo.update(list, listFunc(response$.getValue(), selected$.getValue()));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment