Skip to content

Instantly share code, notes, and snippets.

@angelo510
Created October 14, 2019 16:26
Show Gist options
  • Save angelo510/b5c9320b1fbb6b82b5998f84ca86531d to your computer and use it in GitHub Desktop.
Save angelo510/b5c9320b1fbb6b82b5998f84ca86531d to your computer and use it in GitHub Desktop.
DropdownComponent extended from BaseFieldComponent
import {
Component,
ContentChildren,
EventEmitter,
forwardRef,
Input,
OnDestroy,
Output,
QueryList,
} from "@angular/core";
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from "@angular/forms";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { parseBooleanAttribute, takeUntilDestroy } from "src/utils";
import { BaseFieldComponent } from "./base-field.component";
import { DropdownItemComponent } from "./dropdown-item.component";
@Component({
selector: "mr-dropdown",
templateUrl: "dropdown.component.html",
styleUrls: ["dropdown.component.scss"],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => DropdownComponent),
},
],
})
export class DropdownComponent<T> extends BaseFieldComponent<T | T[]>
implements ControlValueAccessor, OnDestroy {
public constructor() {
super();
this.searchTermChanges
.pipe(
debounceTime(200),
distinctUntilChanged(),
takeUntilDestroy(this),
)
.subscribe(term => {
this.searchTerm.emit(term);
});
}
@Input() public set multiple(value: boolean | string | undefined) {
this.isMultiple = parseBooleanAttribute(value);
}
@Input() public set items(value: ReadonlyArray<T> | undefined) {
this.hasItems = true;
this._items = value;
}
public get items(): ReadonlyArray<T> | undefined {
return this._items;
}
@Input() public valueProperty?: string;
@Input() public displayProperty?: string;
@Input() public placeholder?: string;
@Input() public maxSelectedItems?: number;
@Input() public compareWith = defaultCompareWith;
@Input() public disableClearing = false;
@Input() public searchable = false;
@Output() public readonly searchTerm: EventEmitter<
string
> = new EventEmitter();
@ContentChildren(DropdownItemComponent)
public options!: QueryList<DropdownItemComponent<T>>;
public isMultiple = false;
public hasItems = false;
public readonly searchTermChanges = new Subject<string>();
private _items?: ReadonlyArray<T>;
public ngOnDestroy(): void {
// This empty method is needed only if takeUntilDestroy is used in this component.
}
}
function hasId(value: unknown): value is { id: unknown } {
return typeof value === "object" && value !== null && "id" in value;
}
function defaultCompareWith<T>(option: T, selected: T): boolean {
return (
option === selected ||
(hasId(option) && hasId(selected) && option.id === selected.id)
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment