Create a dropdown component

前端 未结 6 1413
我寻月下人不归
我寻月下人不归 2020-12-08 15:39

I want to create a dropdown menu using Angular 2, but I\'m not sure how to do it in the \"Angular 2 way\".

I could create a dropdown component that is used like this

相关标签:
6条回答
  • 2020-12-08 16:00

    I would say that it depends on what you want to do.

    If your dropdown is a component for a form that manages a state, I would leverage the two-way binding of Angular2. For this, I would use two attributes: an input one to get the associated object and an output one to notify when the state changes.

    Here is a sample:

    export class DropdownValue {
      value:string;
      label:string;
    
      constructor(value:string,label:string) {
        this.value = value;
        this.label = label;
      }
    }
    
    @Component({
      selector: 'dropdown',
      template: `
        <ul>
          <li *ngFor="let value of values" (click)="select(value.value)">{{value.label}}</li>
        </ul>
      `
    })
    export class DropdownComponent {
      @Input()
      values: DropdownValue[];
    
      @Input()
      value: string[];
    
      @Output()
      valueChange: EventEmitter;
    
      constructor(private elementRef:ElementRef) {
        this.valueChange = new EventEmitter();
      }
    
      select(value) {
        this.valueChange.emit(value);
      }
    }
    

    This allows you to use it this way:

    <dropdown [values]="dropdownValues" [(value)]="value"></dropdown>
    

    You can build your dropdown within the component, apply styles and manage selections internally.

    Edit

    You can notice that you can either simply leverage a custom event in your component to trigger the selection of a dropdown. So the component would now be something like this:

    export class DropdownValue {
      value:string;
      label:string;
    
      constructor(value:string,label:string) {
        this.value = value;
        this.label = label;
      }
    }
    
    @Component({
      selector: 'dropdown',
      template: `
        <ul>
          <li *ngFor="let value of values" (click)="selectItem(value.value)">{{value.label}}</li>
        </ul>
      `
    })
    export class DropdownComponent {
      @Input()
      values: DropdownValue[];
    
      @Output()
      select: EventEmitter;
    
      constructor() {
        this.select = new EventEmitter();
      }
    
      selectItem(value) {
        this.select.emit(value);
      }
    }
    

    Then you can use the component like this:

    <dropdown [values]="dropdownValues" (select)="action($event.value)"></dropdown>
    

    Notice that the action method is the one of the parent component (not the dropdown one).

    0 讨论(0)
  • 2020-12-08 16:01

    If you want something with a dropdown (some list of values) and a user specified value that can be filled into the selected input as well. This custom dropdown in angular also has a filter dropdown list on key value entered. Please check this stackblitzlink -> https://stackblitz.com/edit/angular-l9guzo?embed=1&file=src/app/custom-textarea.component.ts

    0 讨论(0)
  • 2020-12-08 16:03

    Hope this will help to someone. Works fine in Angular 6 with reactive forms. Can operate by keyboard too.

    dropdown.component.html

    <div class="dropdown-wrapper {{className}} {{isFocused ? 'focus':''}}" [ngClass]="{'is-open':isOpen, 'disabled':isReadOnly}" *ngIf="options" (contextmenu)="$event.stopPropagation();">
      <div class="box" (click)="toggle($event)">
        <ng-container>
          <div class="dropdown-selected" *ngIf="isSelectedValue" l10nTranslate><span>{{options[selected]}}</span></div>
          <div class="dropdown-selected" *ngIf="!isSelectedValue" l10nTranslate><span>{{placeholder}}</span></div>
        </ng-container>
      </div>
    
      <ul class="dropdown-options" *ngIf="options">
        <li *ngIf="placeholder" (click)="$event.stopPropagation()">{{placeholder}}</li>
        <ng-container>
          <li id="li{{i}}"
            *ngFor="let option of options; let i = index"
            [class.active]="selected === i"
            (click)="optionSelect(option, i, $event)"
            l10nTranslate
          >
            {{option}}
          </li>
        </ng-container>
    
      </ul>
    </div>
    

    dropdown.component.scss

    @import "../../../assets/scss/variables";
    
    // DROPDOWN STYLES
    .dropdown-wrapper {
        display: -webkit-box;
        display: -ms-flexbox;
        display: flex;
        border: 1px solid #DDDDDD;
        border-radius: 3px;
        cursor: pointer;
        position: relative;
        &.focus{
            border: 1px solid #a8a8a8;
        }
        .box {
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            width: 100%;
        } 
    
        // SELECTED
        .dropdown-selected {
            height: 30px;
            position: relative;
            padding: 10px 30px 10px 10px;
            display: -webkit-box;
            display: -ms-flexbox;
            display: flex;
            -webkit-box-align: center;
                -ms-flex-align: center;
                    align-items: center;
            width: 100%;
            font-size: 12px;
            color: #666666;
            overflow: hidden;
            background-color: #fff;
            &::before {
                content: "";
                position: absolute;
                top: 50%;
                right: 5px;
                -webkit-transform: translateY(-50%);
                        transform: translateY(-50%);
                width: 22px;
                height: 22px;
                background: url('/assets/i/dropdown-open-selector.svg');
                background-size: 22px 22px;
            }
            span {
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
        } 
    
        // DROPDOWN OPTIONS
        .dropdown-options {
            display: none;
            position: absolute;
            padding: 8px 6px 9px 5px;
            max-height: 261px;
            overflow-y: auto;
            z-index: 999;
            li {
                padding: 10px 25px 10px 10px;
                font-size: $regular-font-size;
                color: $content-text-black;
                position: relative;
                line-height: 10px;
                &:last-child {
                    border-bottom: none;
                }
                &:hover {
                    background-color: #245A88;
                    border-radius: 3px;
                    color: #fff;
                    border-bottom-color: transparent;
                }
                &:focus{
                    background-color: #245A88;
                    border-radius: 3px;
                    color: #fff;
                }
                &.active {
                    background-color: #245A88;
                    border-radius: 3px;
                    color: #fff;
                    border-bottom-color: transparent;
                }
                &:hover {
                    background-color: #7898B3
                }
                &.active {
                    font-weight: 600;
                }
            }
        }
        &.is-open {
            .dropdown-selected {
                &::before {
                    content: "";
                    position: absolute;
                    top: 50%;
                    right: 5px;
                    -webkit-transform: translateY(-50%);
                            transform: translateY(-50%);
                    width: 22px;
                    height: 22px;
                    background: url('/assets/i/dropdown-close-selector.svg');
                    background-size: 22px 22px;
                }
            }
            .dropdown-options {
                display: -webkit-box;
                display: -ms-flexbox;
                display: flex;
                -webkit-box-orient: vertical;
                -webkit-box-direction: normal;
                    -ms-flex-direction: column;
                        flex-direction: column;
                width: 100%;
                top: 32px;
                border-radius: 3px;
                background-color: #ffffff;
                border: 1px solid #DDDDDD;
                -webkit-box-shadow: 0px 3px 11px 0 rgba(1, 2, 2, 0.14);
                        box-shadow: 0px 3px 11px 0 rgba(1, 2, 2, 0.14);
            }
        }
        &.data-input-fields {
            .box {
                height: 35px;
            }
        }
        &.send-email-table-select {
            min-width: 140px;
            border: none;
        }
        &.persoanal-settings {
            width: 80px;
        }
    }
    
    div.dropdown-wrapper.disabled
    {
      pointer-events: none;
      background-color: #F1F1F1;
      opacity: 0.7;
    }
    

    dropdown.component.ts

    import { Component, OnInit, Input, Output, EventEmitter, HostListener, forwardRef } from '@angular/core';
    import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
    
    const noop = () => {
    };
    
    export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DropdownComponent),
      multi: true
    };
    
    @Component({
      selector: 'app-dropdown',
      templateUrl: './dropdown.component.html',
      styleUrls: ['./dropdown.component.scss'],
      providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
    })
    export class DropdownComponent implements OnInit, ControlValueAccessor {
    
      @Input() options: Array<string>;
      @Input() selected: number;
      @Input() className: string;
      @Input() placeholder: string;
      @Input() isReadOnly = false;
      @Output() optSelect = new EventEmitter();
      isOpen = false;
      selectedOption;
    
    
      private onTouchedCallback: () => void = noop;
      private onChangeCallback: (_: any) => void = noop;
      isSelectedValue: boolean;
      key: string;
      isFocused: boolean;
    
      /**
       *Creates an instance of DropdownComponent.
       * @memberof DropdownComponent
       */
    
      ngOnInit() {
        // Place default value in dropdown
        if (this.selected) {
          this.placeholder = '';
          this.isOpen = false;
        }
      }
    
      @HostListener('focus')
      focusHandler() {
        this.selected = 0;
        this.isFocused = true;
      }
    
      @HostListener('focusout')
      focusOutHandler() {
        this.isFocused = false;
      }
    
      @HostListener('document:keydown', ['$event'])
      keyPressHandle(event: KeyboardEvent) {
    
        if (this.isFocused) {
          this.key = event.code;
          switch (this.key) {
            case 'Space':
              this.isOpen = true;
              break;
            case 'ArrowDown':
              if (this.options.length - 1 > this.selected) {
                this.selected = this.selected + 1;
              }
              break;
            case 'ArrowUp':
              if (this.selected > 0) {
                this.selected = this.selected - 1;
              }
              break;
            case 'Enter':
              if (this.selected > 0) {
                this.isSelectedValue = true;
                this.isOpen = false;
                this.onChangeCallback(this.selected);
                this.optSelect.emit(this.options[this.selected]);
              }
              break;
          }
        }
    
      }
    
      /**
      * option selection
      * @param {string} selectedOption - text
      * @param {number} idx - current index of item
      * @param {any} event - object
      */
      optionSelect(selectedOption: string, idx, e: any) {
        e.stopPropagation();
        this.selected = idx;
        this.isSelectedValue = true;
        // this.placeholder = '';
        this.isOpen = false;
        this.onChangeCallback(this.selected);
        this.optSelect.emit(selectedOption);
      }
    
      /**
      * toggle the dropdown
      * @param {any} event object
      */
      toggle(e: any) {
        e.stopPropagation();
        // close all previously opened dropdowns, before open
        const allElems = document.querySelectorAll('.dropdown-wrapper');
        for (let i = 0; i < allElems.length; i++) {
          allElems[i].classList.remove('is-open');
        }
        this.isOpen = !this.isOpen;
        if (this.selected >= 0) {
          document.querySelector('#li' + this.selected).scrollIntoView(true);
        }
      }
    
      /**
      * dropdown click on outside
      */
      @HostListener('document: click', ['$event'])
      onClick() {
        this.isOpen = false;
      }
    
      /**
       * Method implemented from ControlValueAccessor and set default selected value
       * @param {*} obj
       * @memberof DropdownComponent
       */
      writeValue(obj: any): void {
        if (obj && obj !== '') {
          this.isSelectedValue = true;
          this.selected = obj;
        } else {
          this.isSelectedValue = false;
        }
      }
    
      // From ControlValueAccessor interface
      registerOnChange(fn: any) {
        this.onChangeCallback = fn;
      }
    
      // From ControlValueAccessor interface
      registerOnTouched(fn: any) {
        this.onTouchedCallback = fn;
      }
    
      setDisabledState?(isDisabled: boolean): void {
    
      }
    
    }
    

    Usage

    <app-dropdown formControlName="type" [options]="types" [placeholder]="captureData.type" [isReadOnly]="isReadOnly">
    </app-dropdown>
    

    Options must bind an array as follows. It can change based on the requirement.

    types= [
            {
                "id": "1",
                "value": "Type 1"
            },
            {
                 "id": "2",
                 "value": "Type 2"
            },
            {
                  "id": "3",
                  "value": "Type 3"
            }] 
    
    0 讨论(0)
  • 2020-12-08 16:14

    If you want to use bootstrap dropdowns, I will recommend this for angular2:

    ngx-dropdown

    0 讨论(0)
  • This is the code to create dropdown in Angular 7, 8, 9

    .html file code

    <div>
    <label>Summary: </label>
    <select (change)="SelectItem($event.target.value)" class="select">
      <option value="0">--All--</option>
      <option *ngFor="let item of items" value="{{item.Id.Value}}">
        {{item.Name}}
      </option>
    </select>
    </div>
    

    .ts file code

    SelectItem(filterVal: any)
    {
        var id=filterVal;
        //code
    }
    

    items is an array which should be initialized in .ts file.

    0 讨论(0)
  • 2020-12-08 16:24

    This might not exactly you want but I've used jquery smartmenu(https://github.com/vadikom/smartmenus) to build a ng2 dropdown menu.

     $('#main-menu').smartmenus();
    

    http://plnkr.co/edit/wLqLUoBQYgcDwOgSoRfF?p=preview https://github.com/Longfld/DynamicaLoadMultiLevelDropDownMenu

    0 讨论(0)
提交回复
热议问题