Skip to content

Instantly share code, notes, and snippets.

@calebergh
Last active April 19, 2018 14:09
Show Gist options
  • Save calebergh/899623183886f0460b134e80e1b42ecc to your computer and use it in GitHub Desktop.
Save calebergh/899623183886f0460b134e80e1b42ecc to your computer and use it in GitHub Desktop.
Fancy Select / Dropdown for Angular
ng-container(*ngIf="via_relay")
ng-template(#loading="")
p.loading.loading-xs.text-left
i.fas.fa-sync-alt.fa-spin
| Loading...
div.dropdown(*ngIf="relay_zones | async; else loading; let relay_zones", tabindex="0", (keyup)="handleKeyup($event, relay_zones)")
input(type="hidden", name="relay_zone", value="", [formControl]="ciscoForm.controls['relay_zone']")
.selected((click)="endpointRelayOpen = !endpointRelayOpen")
span.status(*ngIf="selectedRelay?.status", [connectionStatus]="selectedRelay.status")
span {{selectedRelay.name}}
.dropdown-options(*ngIf="endpointRelayOpen")
.dropdown-option(*ngFor="let relay of relays.data", (click)="setSelectedRelay(relay); endpointRelayOpen=false;", [class.active]="selectedRelay.id == relay.id")
i.far.fa-eye
| {{relay.name}}
$light-grey: #ccc;
$dark-grey: #888;
// this is a SCSS placeholder, and is only included if it is extended
%fa-custom {
// extending this will require setting something like content: $fa-var-caret-down;
font-family: "Font Awesome\ 5 Free";
/* default to 900 (free solid), other valid options are 400 (free regular and regular brands) */
font-weight: 900;
-webkit-font-smoothing: antialiased;
}
.dropdown {
max-width: 250px;
position: relative;
cursor: pointer;
.selected {
border: 1px solid $dark-grey;
padding: 3px 25px 3px 5px;
overflow: hidden;
width: 100%;
box-sizing: border-box;
&:after {
@extend %fa-custom;
// relies on FontAwesome 5 Angular module
content: fa-content($fa-var-caret-down);
display: inline-block;
position: absolute;
top: 0;
right: 0;
padding: 6px 8px;
border-left: 1px solid $light-grey;
}
}
.dropdown-options {
position: absolute;
top: 25px;
z-index: 255555;
border: 1px solid $light-grey;
box-shadow: 2px 2px 4px $light-grey;
background: white;
box-sizing: border-box;
width: 100%;
}
.dropdown-option {
padding: 3px 5px;
& + .dropdown-option {
border-top: 1px solid $light-grey
}
&.active,
&:hover {
background: $lighter-grey;
}
i.far {
margin-right: 4px;
}
}
}
import * as _ from 'lodash';
import {Component, OnInit, OnDestroy} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
import {Observable} from 'rxjs';
@Component({
selector: 'my-form',
template: require('./form.pug')
})
export class FormComponent implements OnInit, OnDestroy {
private endpoint: any;
private relay_zones: Observable<any>;
private endpointRelayOpen: boolean = false;
setEndpointFormValue(formName: string, values: object) {
this[formName].patchValue(values);
}
setSelectedRelay(relay: IRelay) {
this.selectedRelay = relay;
this.setEndpointFormValue('ciscoForm', {relay_zone: relay.id});
}
/**
* Accessibility for custom Dropdown (for relays)
* @param {*} $event
* @param {*} records
*/
handleKeyup($event: any, records: any) {
// it appears that angular passes strings representing the keycodes, rather than numbers. nice.
// tab only fires when dropdown _receives_ focus, not when blurring. Causes issues, so stop here
if ('Tab' === $event.code) {
return;
}
// passed-in records are the full subscription response, attempt to drill into the "data" portion
records = _.get(records, 'data', records);
// space and enter will open / close the dropdown
if ('Space' === $event.code || 'Enter' === $event.code) {
this.endpointRelayOpen = !this.endpointRelayOpen;
return;
}
let currentIndex = _.findIndex(records, {id: _.get(this.selectedRelay, 'id')});
// move up / down with the arrow keys
if ('ArrowDown' === $event.code) {
currentIndex += 1;
} else if ('ArrowUp' === $event.code) {
currentIndex -= 1;
}
// ensure within range. provide "wrapping" off the end / beginning
if (currentIndex < 0) {
currentIndex = (records.length - 1);
} else if (currentIndex >= records.length) {
currentIndex = 0;
}
this.setSelectedRelay(records[currentIndex]);
}
ngOnInit() {
this.relay_zones = this.API.getObservable('RelayZones');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment