Skip to content

Instantly share code, notes, and snippets.

@winterlimelight
Last active January 30, 2020 05:41
Show Gist options
  • Save winterlimelight/38fe887a3e39beee880ef65f611ab1ae to your computer and use it in GitHub Desktop.
Save winterlimelight/38fe887a3e39beee880ef65f611ab1ae to your computer and use it in GitHub Desktop.
Aurelia Typeahead
<!-- See https://winterlimelight.com/2017/02/21/typeahead-and-aurelia/ for details on prepare-query -->
<contractui-element-typeahead
style="display: inline-block"
initial-value.bind="value"
labeltext=""
hinttext="Type a..."
prepare-query.bind="prepareQueryFn"
on-select.call="processResult(suggestion)">
</contractui-element-typeahead>
<template>
<require from="../../css/typeaheadjs.css"></require>
<div class="form-group">
<label if.bind="!!labeltext" for="${inputId}">${labeltext}</label>
<input type="text" id="${inputId}" class="form-control" placeholder="${hinttext}" spellcheck="off" autocomplete="off"></input>
</div>
</template>
import { customElement, bindable, bindingMode, autoinject } from 'aurelia-framework';
import 'jquery';
import 'Bloodhound';
import 'typeahead';
let nextId = 1;
@customElement('winter-limelight-element-typeahead')
@autoinject
export class TypeAhead
{
@bindable prepareQuery: Function;
@bindable onSelect: Function;
@bindable hinttext: string;
@bindable labeltext: string;
@bindable({ defaultBindingMode: bindingMode.oneWay }) initialValue: any;
private inputId = "ta-" + nextId++;
private suggestionEngine: Bloodhound<any>;
private typeahead: JQuery;
constructor(private element: Element) {
this.suggestionEngine = new Bloodhound<any>({
datumTokenizer: Bloodhound.tokenizers.whitespace,
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'http://set-by-interceptor',
prepare: (query, settings) => this.prepareQuery(query, settings),
rateLimitWait: 500 //ms
}
});
this.suggestionEngine.initialize();
}
attached() {
let options: Twitter.Typeahead.Options = { minLength: 2 };
let dataset: Twitter.Typeahead.Dataset<any> = {
source: this.suggestionEngine,
async: true,
limit: 10, // needs to be same as whatever is fetched by api
display: res => res.name
};
let ele = jQuery(this.element).find("input");
this.typeahead = ele.typeahead(options, [dataset]);
if(this.initialValue)
this.setValue(this.initialValue);
this.typeahead.on('typeahead:select', (ev, suggestion) => {
this.onSelect({ suggestion: suggestion });
});
}
initialValueChanged() {
this.setValue(this.initialValue)
}
private setValue(valueObj) {
if(!this.typeahead) return;
let value = valueObj && valueObj.name ? valueObj.name : "";
var typeaheadInput = this.typeahead.data('ttTypeahead').input;
// Typeahead doesn't seem to fully sync objects (https://github.com/valor-software/ng2-bootstrap/issues/749)
// so we just set the display correctly. This relies on the assumption that the underlying value for this field
// is being stored in the class using typeahead, and updated via the onSelect below. In effect, if the user doesn't
// change anything the UI will appear to be right and the backing field will be unchanged, and if they do change
// something then the normal process for onSelect() will apply and return a full object.
typeaheadInput.setQuery(value);
typeaheadInput.resetInputValue();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment