<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 Dropdown - Example</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- CSS file -->
    <link rel="stylesheet" type="text/css" href="style.css">
   <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" >

    <!-- IE polyfills, keep the order please -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.33.3/es6-shim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.20/system-polyfills.js"></script>
    
    <!-- Agular 2 -->
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/tools/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.7/angular2.dev.js"></script>
     
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
   
     
     <!-- Config Agular 2 and Typescript -->
    <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {'app': {defaultExtension: 'ts'}} 
      });
      System.import('app/main')
            .then(null, console.error.bind(console));
    </script>

  </head>
 
  <!-- Run the application -->
  <body>
    <h1>Angular 2 Dropdown</h1> 
    <my-app class="container" style="display: block">Loading Sample...</my-app>
  
    <div style="padding-top:50px">
    <a target="_blank" href="http://www.angulartypescript.com/angular-2-tutorial/" title="Angular 2 Tutorial"> 
     <img src="http://www.angulartypescript.com/wp-content/uploads/2016/03/learn-more-angular-2.png" alt="Smiley face" height="200" width="500">   
    </a>  
        <ul class="nav nav-pills nav-stacked" >
            <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-tutorial/" title="Angular 2 Home"> Angular 2 Tutorial </a></li>
          <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-introduction/">Angular 2 Introduction</a></li>
          <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-architecture/">Angular 2 Architecture</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-annotations/">Angular 2 Annotations</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-getting-started/">Angular 2 Setup</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-hello-world/">Angular 2 Hello World</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-components/">Angular 2 Components</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-template-syntax/">Angular 2 Template Syntax</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-data-binding/">Angular 2 Data Binding</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-forms/">Angular 2 Forms</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-formbuilder-example/">Angular 2 Formbuilder</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-router-example/">Angular 2 Router</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-http-example-typescript/">Angular 2 HTTP</a></li>
      <li><a target="_blank" href="http://www.angulartypescript.com/angular-2-services/">Angular 2 Service</a></li> 
    
        </ul>
    </div> 
  </body>

</html>
<!-- 
Copyright 2016 angulartypescript.com. All Rights Reserved.
Everyone can use this source code; don’t forget to indicate the source please:
http://www.angulartypescript.com/ 
-->

/* Styles go here */

/**
 * Created by Tareq Boulakjar. from angulartypescript.com
 */
import {bootstrap}  from 'angular2/platform/browser';
import {Angular2Dropdown} from './dropdown-example';

bootstrap(Angular2Dropdown);


/*
Copyright 2016 angulartypescript.com. All Rights Reserved.
Everyone can use this source code; don’t forget to indicate the source please:
http://www.angulartypescript.com/ 
*/
import {
    Directive,
    OnInit, OnDestroy, Input, Output, HostBinding,
    EventEmitter, ElementRef, ContentChildren,
    Query, QueryList
} from 'angular2/core';

import {dropdownService, NONINPUT} from './dropdown.service';

@Directive({selector: '[dropdown]'})
export class Dropdown implements OnInit, OnDestroy {
    @HostBinding('class.open')
    @Input() public get isOpen():boolean {
        return this._isOpen;
    }

    @Input() public autoClose:string;
    @Input() public keyboardNav:boolean;
    @Input() public appendToBody:boolean;

    @Output() public onToggle:EventEmitter<boolean> = new EventEmitter();
    @Output() public isOpenChange:EventEmitter<boolean> = new EventEmitter();
    @HostBinding('class.dropdown') private addClass = true;

    private _isOpen:boolean;
    // index of selected element
    public selectedOption:number;
    // drop menu html
    public menuEl:ElementRef;
    // drop down toggle element
    public toggleEl:ElementRef;

    constructor(public el:ElementRef,
                @Query('dropdownMenu', {descendants: false}) dropdownMenuList:QueryList<ElementRef>) {
     }

    public set isOpen(value) {
        this._isOpen = !!value;

         if (this.appendToBody && this.menuEl) {

        }

         if (this.isOpen) {
            this.focusToggleElement();
            dropdownService.open(this);
        } else {
            dropdownService.close(this);
            this.selectedOption = null;
        }
        this.onToggle.emit(this.isOpen);
        this.isOpenChange.emit(this.isOpen);
     }

    ngOnInit() {
        this.autoClose = this.autoClose || NONINPUT;
        if (this.isOpen) {
         }
    }

    ngOnDestroy() {
        if (this.appendToBody && this.menuEl) {
            this.menuEl.nativeElement.remove();
        }
    }

    public set dropDownMenu(dropdownMenu:{el:ElementRef}) {
        // init drop down menu
        this.menuEl = dropdownMenu.el;

        if (this.appendToBody) {
            window.document.body.appendChild(this.menuEl.nativeElement);
        }
    }

    public set dropDownToggle(dropdownToggle:{el:ElementRef}) {
        // init toggle element
        this.toggleEl = dropdownToggle.el;
    }

    public toggle(open?:boolean):boolean {
        return this.isOpen = arguments.length ? !!open : !this.isOpen;
    }

    public focusDropdownEntry(keyCode:number) {
        // If append to body is used.
        let hostEl = this.menuEl ?
            this.menuEl.nativeElement :
            this.el.nativeElement.getElementsByTagName('ul')[0];

        if (!hostEl) {
             return;
        }

        let elems = hostEl.getElementsByTagName('a');
        if (!elems || !elems.length) {
             return;
        }

         switch (keyCode) {
            case (40):
                if (typeof this.selectedOption !== 'number') {
                    this.selectedOption = 0;
                    break;
                }

                if (this.selectedOption === elems.length - 1) {
                    break;
                }

                this.selectedOption++;
                break;
            case (38):
                if (typeof this.selectedOption !== 'number') {
                    return;
                }

                if (this.selectedOption === 0) {
                    // todo: return?
                    break;
                }

                this.selectedOption--;
                break;
        }

        elems[this.selectedOption].focus();
    }

    public focusToggleElement() {
        if (this.toggleEl) {
            this.toggleEl.nativeElement.focus();
        }
    }
}
import {ElementRef} from 'angular2/core';

export interface DropdownMenuInterface {
    el: ElementRef;
    templateUrl: string;
}

export interface DropdownToggleInterface {
    el: ElementRef;
}
export const ALWAYS = 'always';
export const DISABLED = 'disabled';
export const OUTSIDECLICK = 'outsideClick';
export const NONINPUT = 'nonInput';

import {Dropdown} from './dropdown.directive';

export class DropdownService {
    private openScope:Dropdown;
    private dropdownScope:Dropdown;

    private closeDropdownBind:EventListener = this.closeDropdown.bind(this);
    private keybindFilterBind:EventListener = this.keybindFilter.bind(this);

    public open(dropdownScope:Dropdown) {
        if (!this.openScope) {
            window.document.addEventListener('click', this.closeDropdownBind);
            window.document.addEventListener('keydown', this.keybindFilterBind);
        }

        if (this.openScope && this.openScope !== this.dropdownScope) {
            this.openScope.isOpen = false;
        }

        this.openScope = dropdownScope;
    }

    public close(dropdownScope:Dropdown) {
        if (this.openScope !== dropdownScope) {
            return;
        }

        this.openScope = null;
        window.document.removeEventListener('click', this.closeDropdownBind);
        window.document.removeEventListener('keydown', this.keybindFilterBind);
    }

    private closeDropdown(event:MouseEvent) {
        if (!this.openScope) {
            return;
        }

        if (event && this.openScope.autoClose === DISABLED) {
            return;
        }

        if (event && this.openScope.toggleEl &&
            this.openScope.toggleEl.nativeElement === event.target) {
            return;
        }

        if (event && this.openScope.autoClose === NONINPUT &&
            this.openScope.menuEl &&
            /input|textarea/i.test((<any> event.target).tagName) &&
            this.openScope.menuEl.nativeElement.contains(event.target)) {
            return;
        }

        if (event && this.openScope.autoClose === OUTSIDECLICK &&
            this.openScope.menuEl &&
            this.openScope.menuEl.nativeElement.contains(event.target)) {
            return;
        }

        this.openScope.isOpen = false;
    }

    private keybindFilter(event:KeyboardEvent) {
        if (event.which === 27) {
            this.openScope.focusToggleElement();
            this.closeDropdown(null);
            return;
        }

        if (this.openScope.keyboardNav && this.openScope.isOpen &&
            (event.which === 38 || event.which === 40)) {
            event.preventDefault();
            event.stopPropagation();
            this.openScope.focusDropdownEntry(event.which);
        }
    }
}

export let dropdownService = new DropdownService();
import {Directive, ElementRef} from 'angular2/core';
import {Dropdown} from './dropdown.directive';

@Directive({
    selector: '[dropdown][dropdownKeyboardNav]',
    host: {
        '(keydown)': 'onKeydown($event)'
    }
})
export class KeyboardNav {
    constructor(private dd:Dropdown, private el:ElementRef) {
        console.warn('keyboard-nav deprecated');
        dd.keyboardNav = true;
    }

    onKeydown(event:KeyboardEvent) {
        if (event.which !== 40 && event.which !== 38) {
            return;
        }

        event.preventDefault();
        event.stopPropagation();

        let elems = this.dd.menuEl.nativeElement.getElementsByTagName('a');

        switch (event.which) {
            case (40):
                if (typeof this.dd.selectedOption !== 'number') {
                    this.dd.selectedOption = 0;
                    break;
                }

                if (this.dd.selectedOption === elems.length - 1) {
                    break;
                }

                this.dd.selectedOption++;
                break;
            case (38):
                if (typeof this.dd.selectedOption !== 'number') {
                    return;
                }

                if (this.dd.selectedOption === 0) {
                    // todo: return?
                    break;
                }

                this.dd.selectedOption--;
                break;
        }
        elems[this.dd.selectedOption].nativeElement.focus();
    }
}
import {
    Directive, ElementRef, Host,
    OnInit
} from 'angular2/core';

import {Dropdown} from './dropdown.directive';

@Directive({ selector: '[dropdownMenu]' })
export class DropdownMenu implements OnInit {
    constructor( @Host() public dropdown: Dropdown, public el: ElementRef) {
    }

    public ngOnInit() {
        this.dropdown.dropDownMenu = this;
    }
}
import {
    Directive, ElementRef, Host,
    OnInit, Input, HostBinding, HostListener
} from 'angular2/core';

import {Dropdown} from './dropdown.directive';

@Directive({ selector: '[dropdownToggle]' })
export class DropdownToggle implements OnInit {
    @HostBinding('class.disabled')
    @Input() private disabled:boolean = false;

    @HostBinding('class.dropdown-toggle')
    @HostBinding('attr.aria-haspopup')
    private addClass = true;

    constructor(@Host() public dropdown:Dropdown, public el:ElementRef) {
    }

    public ngOnInit() {
        this.dropdown.dropDownToggle = this;
    }

    @HostBinding('attr.aria-expanded')
    public get isOpen() {
        return this.dropdown.isOpen;
    }

    @HostListener('click', ['$event'])
    public toggleDropdown(event:MouseEvent) {
        event.stopPropagation();

        if (!this.disabled) {
            this.dropdown.toggle();
        }
        return false;
    }
}
/**
 * Created by Tareq Boulakjar. from angulartypescript.com
 */
import {Component} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
import {Dropdown} from './dropdown.directive';
import {DropdownMenu} from './dropdown-menu.directive';
import {DropdownToggle} from './dropdown-toggle.directive';

/*Angular 2 Dropdown Menu*/
@Component({
    selector: 'my-app',
    template: `

                    <div (click)="$event.preventDefault()">
                      <!-- Angular 2 Simple Dropdown Menu -->
                      <h4>Angular 2 Simple Dropdown Menu</h4>
                      <span dropdown>
                        <a href id="angular-simple-dropdown" dropdownToggle>
                                angular 2 simple dropdown menu
                        </a>
                        <ul class="dropdown-menu" aria-labelledby="angular-simple-dropdown">
                          <li *ngFor="#item of dropDownItemsExample">
                            <a class="dropdown-item" href="#">{{item}}</a>
                          </li>
                        </ul>
                      </span>
                      <hr>
                      <!-- Angular 2 Dropdown Menu with Enable/Disable mode and Events (external click) -->
                      <h4>Angular 2 Dropdown Menu with Enable/Disable mode and Events (external click)</h4>
                      <div>
                        <button type="button" class="btn btn-warning btn-sm" (click)="dropdownMenu($event)">Dropdown Menu (Toggle)
                        </button>
                        <button type="button" class="btn btn-danger btn-sm" (click)="disabledMenu = !disabledMenu">Enable/Disable Dropdown Menu</button>
                      </div>
                      <div class="btn-group" dropdown [(isOpen)]="status.isopen">
                        <button id="dropdown-list" type="button" class="btn btn-default" dropdownToggle [disabled]="disabledMenu">
                          Button dropdown <span class="caret"></span>
                        </button>
                        <ul class="dropdown-menu" role="menu" aria-labelledby="dropdown-list">
                          <li role="menuitem"><a class="dropdown-item" href="#">Audi</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">BMW</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">Mercedes</a></li>
                          <li class="divider dropdown-divider"></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">Maserati</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">Porsche</a></li>
                        </ul>
                      </div>

                      <hr>

                      <!-- Angular 2 Dropdown Menu with Keyboard Accessibility -->
                      <h4>Angular 2 Dropdown Menu with Keyboard Accessibility</h4>
                      <div class="btn-group" dropdown keyboardNav="true">
                        <button id="dropdown-keyboard-access" type="button" class="btn btn-info" dropdownToggle>
                          Dropdown with Keyboard Accessibility (Up and Down) <span class="caret"></span>
                        </button>
                        <ul class="dropdown-menu" role="menu" aria-labelledby="dropdown-keyboard-access">
                          <li role="menuitem"><a class="dropdown-item" href="#">BMW Serie 1</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">BMW Serie 5</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">BMW Serie 3</a></li>
                          <li class="divider dropdown-divider"></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">Porsche</a></li>
                          <li role="menuitem"><a class="dropdown-item" href="#">Audi New</a></li>
                        </ul>
                      </div>
                    </div>
               `,
    directives: [ Dropdown, DropdownMenu, DropdownToggle, CORE_DIRECTIVES],
 })
export class Angular2Dropdown {

    private disabledMenu:boolean = false;

    private status:{isopen:boolean} = {isopen: false};

    private dropDownItemsExample:Array<string> = ['BMW Serie 1', 'BMW Serie 2', 'BMW Serie 3', 'BMW Serie 4'];

    private dropdownMenu($event:MouseEvent):void {
        $event.preventDefault();
        $event.stopPropagation();
        this.status.isopen = !this.status.isopen;
    }

}