Created
January 25, 2016 08:40
-
-
Save maggiben/678fa214a207d0e50107 to your computer and use it in GitHub Desktop.
Aurelia typeahead
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<require from="/styles/type-ahead.css"></require> | |
<div class="ui icon input"> | |
<input type="text" class="form-control" placeholder.bind="options.placeholder" value.bind="value"> | |
<i class="search link icon"></i> | |
</div> | |
</template> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {ViewCompiler, ViewResources, inject, customElement, Container, bindable} from 'aurelia-framework'; | |
import {TemplateRegistryEntry, Loader} from 'aurelia-loader'; | |
import {HttpClient} from 'aurelia-http-client'; | |
import typeahead from 'typeahead'; | |
import Rx from 'rx'; | |
@inject(Element, HttpClient, Loader, ViewResources, ViewCompiler, Container) | |
@bindable('value') | |
@bindable('options') | |
@customElement('type-ahead') | |
export class TypeAhead { | |
constructor(element, http, loader, viewResources, viewCompiler, container) { | |
this.element = element; | |
this.http = http; | |
this.loader = loader; | |
this.viewResources = viewResources; | |
this.viewCompiler = viewCompiler; | |
this.container = container; | |
} | |
searchTerm(term) { | |
return new HttpClient() | |
.createRequest('api/v2/Lookup/jsonp') | |
.asJsonp() | |
.withBaseUrl('http://dev.markitondemand.com') | |
.withParams({ | |
input: term | |
}) | |
.withCallbackParameterName('callback') | |
.send() | |
.then(function(result) { | |
return result.response.map(function(item, index){ | |
return { | |
symbol: item.Symbol, | |
name: item.Name, | |
exchange: item.Exchange | |
}; | |
}); | |
}); | |
} | |
getSuggestions() { | |
//var keyup = Rx.Observable.fromEvent($(this.element).find('input'), 'keyup') | |
var keyup = Rx.Observable.fromEvent($(this.element), 'typeahead:asyncrequest') | |
.map(function (e) { | |
return e.target.value; // Project the text from the input | |
}) | |
.filter(function (text) { | |
var regex = new RegExp('^[a-zA-Z0-9_ ]*$'); // Match only alphanumric underscore and space | |
return regex.test(text); | |
}) | |
.debounce(750) | |
.distinctUntilChanged(); // Only if the value has changed | |
var searcher = keyup.flatMapLatest(this.searchTerm); | |
this.searcher = searcher; | |
return (query, syncResults, asyncResults) => { | |
var subscription = this.searcher.first().subscribe( | |
(data) => { | |
return asyncResults(data); | |
}, | |
function (error) { | |
return asyncResults([]); | |
} | |
); | |
}; | |
} | |
attached() { | |
var options = { | |
hint: true, | |
async: true, | |
highlight: true, | |
minLength: 2, | |
display: 'symbol' | |
}; | |
var datasets = [{ | |
name: 'tickers', | |
//valueKey: this.options.valueKey, | |
limit: 4, | |
displayKey: 'symbol', | |
source: this.getSuggestions() | |
}] | |
this.loader.loadTemplate('components/styles/type-ahead-templates.html') | |
.then((templateRegistryEntry) => { | |
let viewFactory = this.viewCompiler.compile(templateRegistryEntry.template, this.viewResources); | |
datasets.forEach(dataset => { | |
dataset.templates = { | |
suggestion: (data) => { | |
// Bind the view and it's children | |
let view = viewFactory.create(this.container, data); | |
view.bind(data); | |
var serializer = new XMLSerializer() | |
return serializer.serializeToString(view.fragment.querySelector('div')); | |
} | |
}; | |
}); | |
options = Object.assign(options, this.options.options); | |
this.typeAhead = $(this.element).find('input').typeahead(options, datasets); | |
this.typeAhead.bind('typeahead:selected', (event, datum, name) => { | |
event = new CustomEvent('selected', { | |
detail: { | |
value: datum | |
}, | |
bubbles: true | |
}); | |
this.element.dispatchEvent(event); | |
}); | |
this.typeAhead.bind('typeahead:autocomplete', (event, datum, name) => { | |
event = new CustomEvent('autocomplete', { | |
detail: { | |
value: datum | |
}, | |
bubbles: true | |
}); | |
this.element.dispatchEvent(event); | |
}); | |
// Typeahead will trigger an 'open' if input gains focus to display suggestions | |
// This in turn triggers antoher async call | |
this.typeAhead.bind('typeahead:asyncrequest', (event, query, name) => { | |
this.isSearching = true; | |
}); | |
this.typeAhead.bind('typeahead:asyncreceive', (event, query, name) => { | |
this.isSearching = false; | |
}); | |
this.typeAhead.bind('typeahead:asynccancel', (event, query, name) => { | |
this.isSearching = false; | |
}); | |
}); | |
} | |
valueChanged(newValue, oldValue) { | |
console.log('valueChanged', newValue) | |
} | |
optionsChanged(newValue, oldValue) { | |
console.log('optionsChanged', newValue) | |
} | |
detached() { | |
$(this.element).typeahead('destroy'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@maggiben May I use this code in a project? I just wanted to check.