Skip to content

Commit

Permalink
fix(typeahead): blur event handler should not prevent item selection
Browse files Browse the repository at this point in the history
fixes #403, fixes #418, fixes #356
  • Loading branch information
valorkin committed Apr 15, 2016
1 parent b1a95d1 commit 847d375
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 15 deletions.
20 changes: 11 additions & 9 deletions components/typeahead/typeahead-container.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {Typeahead} from './typeahead.directive';
import {TypeaheadOptions} from './typeahead-options.class';
import {positionService} from '../position';
import {Ng2BootstrapConfig, Ng2BootstrapTheme} from '../ng2-bootstrap-config';

const TEMPLATE:any = {
[Ng2BootstrapTheme.BS4]: `
<div class="dropdown-menu"
style="display: block"
[ngStyle]="{top: top, left: left, display: display}"
style="display: block">
(mouseleave)="focusLost()">
<a href="#"
*ngFor="#match of matches"
class="dropdown-item"
Expand All @@ -22,8 +22,9 @@ const TEMPLATE:any = {
`,
[Ng2BootstrapTheme.BS3]: `
<ul class="dropdown-menu"
style="display: block"
[ngStyle]="{top: top, left: left, display: display}"
style="display: block">
(mouseleave)="focusLost()">
<li *ngFor="#match of matches"
[class.active]="isActive(match)"
(mouseenter)="selectActive(match)">
Expand All @@ -32,7 +33,6 @@ const TEMPLATE:any = {
</ul>
`
};

@Component({
selector: 'typeahead-container',
directives: [CORE_DIRECTIVES],
Expand All @@ -43,9 +43,10 @@ export class TypeaheadContainer {
public parent:Typeahead;
public query:any;
public element:ElementRef;
public isFocused:boolean = false;
private _active:any;
private _matches:Array<any> = [];
private _field:string;
private _active:any;
private top:string;
private left:string;
private display:string;
Expand All @@ -62,7 +63,6 @@ export class TypeaheadContainer {

public set matches(value:Array<string>) {
this._matches = value;

if (this._matches.length > 0) {
this._active = this._matches[0];
}
Expand Down Expand Up @@ -103,6 +103,7 @@ export class TypeaheadContainer {
}

protected selectActive(value:any):void {
this.isFocused = true;
this._active = value;
}

Expand All @@ -115,7 +116,6 @@ export class TypeaheadContainer {
: itemStr).toLowerCase();
let startIdx:number;
let tokenLen:number;

// Replaces the capture string with the same string inside of a "strong" tag
if (typeof query === 'object') {
let queryLen:number = query.length;
Expand All @@ -136,7 +136,6 @@ export class TypeaheadContainer {
itemStr = itemStr.substring(0, startIdx) + '<strong>' + itemStr.substring(startIdx, startIdx + tokenLen) + '</strong>' + itemStr.substring(startIdx + tokenLen);
}
}

return itemStr;
}

Expand All @@ -149,11 +148,14 @@ export class TypeaheadContainer {
e.stopPropagation();
e.preventDefault();
}

this.parent.changeModel(value);
this.parent.typeaheadOnSelect.emit({
item: value
});
return false;
}

private focusLost():void {
this.isFocused = false;
}
}
3 changes: 3 additions & 0 deletions components/typeahead/typeahead-options.class.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {Typeahead}from './typeahead.directive';

export class TypeaheadOptions {
public placement:string;
public animation:boolean;
public typeaheadRef:Typeahead;

public constructor(options:TypeaheadOptions) {
Object.assign(this, options);
Expand Down
36 changes: 30 additions & 6 deletions components/typeahead/typeahead.directive.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
Directive, Input, Output, HostListener, EventEmitter, OnInit, ElementRef,
Renderer, DynamicComponentLoader, ComponentRef, Provider, Injector
Renderer, DynamicComponentLoader, ComponentRef, Injector, provide
} from 'angular2/core';
import {NgModel} from 'angular2/common';
import {TypeaheadUtils} from './typeahead-utils';
Expand Down Expand Up @@ -41,12 +41,14 @@ export class Typeahead implements OnInit {
// @Input() private typeaheadFocusOnSelect:boolean;

public container:TypeaheadContainer;
public isTypeaheadOptionsListActive:boolean = false;

private debouncer:Function;
private _matches:Array<any> = [];
private placement:string = 'bottom-left';
private popup:Promise<ComponentRef>;


private cd:NgModel;
private element:ElementRef;
private renderer:Renderer;
Expand Down Expand Up @@ -102,15 +104,36 @@ export class Typeahead implements OnInit {

@HostListener('blur', ['$event.target'])
protected onBlur():void {
// Allow typeahead container click event to be triggered requires a timeout
setTimeout(this.hide.bind(this), 10);
console.log('blur')
if (this.container && !this.container.isFocused) {
console.log('blur hide')
this.hide();
}
}

@HostListener('keydown', ['$event'])
protected onKeydown(e:KeyboardEvent):void {
// When typeahead container is visible, prevent submitting the form
if (this.container && e.keyCode === 13) {
// no container - no problems
if (!this.container) {
return;
}

// if items is visible - prevent form submition
if (e.keyCode === 13) {
e.preventDefault();
return;
}

// if shift + tab, close items list
if (e.shiftKey && e.keyCode === 9) {
this.hide();
return;
}

// if tab select current item
if (!e.shiftKey && e.keyCode === 9) {
this.container.selectActiveMatch();
return;
}
}

Expand Down Expand Up @@ -166,12 +189,13 @@ export class Typeahead implements OnInit {

public show(matches:Array<any>):void {
let options = new TypeaheadOptions({
typeaheadRef: this,
placement: this.placement,
animation: false
});

let binding = Injector.resolve([
new Provider(TypeaheadOptions, {useValue: options})
provide(TypeaheadOptions, {useValue: options})
]);

this.popup = this.loader
Expand Down

0 comments on commit 847d375

Please sign in to comment.