Implement autocomplete for angular2

I'm having trouble finding a good autocomplete component for Angular2. It's just that I can pass a list of keys, tag objects and have a good autocomplete in the input field. Kendo does not yet support angular2 and that is what we mainly use internally. It looks like angular stuff supports angular 2. Can someone point me in the right direction or tell me what they are using?

This is what I have created so far. This is pretty bad and I would like to find something that looks good.

import {Component, EventEmitter, Input, Output} from 'angular2/core'; import {Control} from 'angular2/common'; import {Observable} from 'rxjs/Observable'; import {SimpleKeyValue} from '../models/simple-key-value' import 'rxjs/add/operator/map'; import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/distinctUntilChanged'; @Component({ selector: 'general-typeahead', template: ` <div> <div class="input-group"> <input type="text" [ngFormControl] = "term" class="form-control" placeholder={{placeHolder}} > </div> <ul> <li class="item" *ngFor="#item of matchingItems" (click)="selectItem(item)"> {{item.value}} </li> </ul> </div>` }) export class GeneralTypeahead { matchingItems: Array<SimpleKeyValue>; term = new Control(); @Input() allItems: Array<SimpleKeyValue>; @Input() placeHolder: string; @Output() onSelectItem = new EventEmitter<SimpleKeyValue>(); constructor() { this.term.valueChanges .distinctUntilChanged() .debounceTime(200) .subscribe((term : string) => this.matchingItems = this.allItems.filter(sl => sl.value.toLowerCase().indexOf(term.toLowerCase()) > -1)); } selectItem(sl: SimpleKeyValue) { this.onSelectItem.emit(sl); } } 
+46
angular angular2-template angular2-directives
Mar 09 '16 at 2:28
source share
7 answers

Update:. This answer led to the development of the ng2-completer Angular2 autocomplete component. This is a list of the autocomplete output components for Angular2:

loan goes to @ dan-cancro for setting off an idea

Keeping the original answer for those who want to create their own directive:

To display an autocomplete list, we first need an attribute directive that returns a list of offers based on the input text and then displays them in a drop-down list. The directive has two options for sorting the list:

  • Get a link to nativeElement and directly manipulate the DOM.
  • Dynamically load a list component using DynamicComponentLoader

It seems to me that the second method is the best choice, since it uses angular 2 main mechanisms instead of going around them, working directly with the DOM, and therefore I will use this method.

This is the directive code:

 "use strict"; import {Directive, DynamicComponentLoader, Input, ComponentRef, Output, EventEmitter, OnInit, ViewContainerRef} from "@angular/core"; import {Promise} from "es6-promise"; import {AutocompleteList} from "./autocomplete-list"; @Directive({ selector: "[ng2-autocomplete]", // The attribute for the template that uses this directive host: { "(keyup)": "onKey($event)" // Liten to keyup events on the host component } }) export class AutocompleteDirective implements OnInit { // The search function should be passed as an input @Input("ng2-autocomplete") public search: (term: string) => Promise<Array<{ text: string, data: any }>>; // The directive emits ng2AutocompleteOnSelect event when an item from the list is selected @Output("ng2AutocompleteOnSelect") public selected = new EventEmitter(); private term = ""; private listCmp: ComponentRef<AutocompleteList> = undefined; private refreshTimer: any = undefined; private searchInProgress = false; private searchRequired = false; constructor( private viewRef: ViewContainerRef, private dcl: DynamicComponentLoader) { } /** * On key event is triggered when a key is released on the host component * the event starts a timer to prevent concurrent requests */ public onKey(event: any) { if (!this.refreshTimer) { this.refreshTimer = setTimeout( () => { if (!this.searchInProgress) { this.doSearch(); } else { // If a request is in progress mark that a new search is required this.searchRequired = true; } }, 200); } this.term = event.target.value; if (this.term === "" && this.listCmp) { // clean the list if the search term is empty this.removeList(); } } public ngOnInit() { // When an item is selected remove the list this.selected.subscribe(() => { this.removeList(); }); } /** * Call the search function and handle the results */ private doSearch() { this.refreshTimer = undefined; // if we have a search function and a valid search term call the search if (this.search && this.term !== "") { this.searchInProgress = true; this.search(this.term) .then((res) => { this.searchInProgress = false; // if the term has changed during our search do another search if (this.searchRequired) { this.searchRequired = false; this.doSearch(); } else { // display the list of results this.displayList(res); } }) .catch(err => { console.log("search error:", err); this.removeList(); }); } } /** * Display the list of results * Dynamically load the list component if it doesn't exist yet and update the suggestions list */ private displayList(list: Array<{ text: string, data: any }>) { if (!this.listCmp) { this.dcl.loadNextToLocation(AutocompleteList, this.viewRef) .then(cmp => { // The component is loaded this.listCmp = cmp; this.updateList(list); // Emit the selectd event when the component fires its selected event (<AutocompleteList>(this.listCmp.instance)).selected .subscribe(selectedItem => { this.selected.emit(selectedItem); }); }); } else { this.updateList(list); } } /** * Update the suggestions list in the list component */ private updateList(list: Array<{ text: string, data: any }>) { if (this.listCmp) { (<AutocompleteList>(this.listCmp.instance)).list = list; } } /** * remove the list component */ private removeList() { this.searchInProgress = false; this.searchRequired = false; if (this.listCmp) { this.listCmp.destroy(); this.listCmp = undefined; } } } 

The directive dynamically loads a dropdown component, this is a sample of such a component using bootstrap 4:

 "use strict"; import {Component, Output, EventEmitter} from "@angular/core"; @Component({ selector: "autocomplete-list", template: `<div class="dropdown-menu search-results"> <a *ngFor="let item of list" class="dropdown-item" (click)="onClick(item)">{{item.text}}</a> </div>`, // Use a bootstrap 4 dropdown-menu to display the list styles: [".search-results { position: relative; right: 0; display: block; padding: 0; overflow: hidden; font-size: .9rem;}"] }) export class AutocompleteList { // Emit a selected event when an item in the list is selected @Output() public selected = new EventEmitter(); public list; /** * Listen for a click event on the list */ public onClick(item: {text: string, data: any}) { this.selected.emit(item); } } 

To use the directive in another component, you need to import the directive, include it in the component directives and provide it with a search function and an event handler to select:

  "use strict"; import {Component} from "@angular/core"; import {AutocompleteDirective} from "../component/ng2-autocomplete/autocomplete"; @Component({ selector: "my-cmp", directives: [AutocompleteDirective], template: `<input class="form-control" type="text" [ng2-autocomplete]="search()" (ng2AutocompleteOnSelect)="onItemSelected($event)" autocomplete="off">` }) export class MyComponent { /** * generate a search function that returns a Promise that resolves to array of text and optionally additional data */ public search() { return (filter: string): Promise<Array<{ text: string, data: any }>> => { // do the search resolve({text: "one item", data: null}); }; } /** * handle item selection */ public onItemSelected(selected: { text: string, data: any }) { console.log("selected: ", selected.text); } } 

Update: Angular2 rc.1 compatible code

+99
Mar 16 '16 at 9:12
source share

PrimeNG has its own AutoComplete component with advanced features such as templating and multiple selection.

http://www.primefaces.org/primeng/#/autocomplete

+17
Mar 24 '16 at 17:14
source share

I think you can use typeahead.js . There are typescript definitions for it. so it will be easy to use it, I think if you use typescript for development.

+2
Mar 10 '16 at 5:50
source share

I know that you already have several answers, but I was in a similar situation when my team did not want to depend on heavy libraries or anything related to downloading, since we use the material, so I made my own autocomplete control using similar to the stuff, you can use autocomplete or at least you can take a look to give you Some examples there was little documentation on simple examples of how to load your components for sharing in NPM.

+1
Nov 18 '16 at 5:01
source share

I created anuglar2 autocomplete module. In this module you can use the npm link array or url: ang2-autocomplete

0
Dec 08 '16 at 2:52
source share

Auto-complete embeddable component in angular material

Click here to check it out !

Note. You can even customize the filter logic of this autocomplete according to your requirements.

0
05 Oct '17 at 10:40 on
source share

Based on the examples above, I created something like this, here is the plunker demo: https://plnkr.co:443/2aL2Ju and github url: https://github.com/creativedeveloper-net/angular2-autocomplete feel free to update / improve it

 to see the code please see attached links 
-2
Oct 25 '16 at 15:31
source share



All Articles