import {
AfterViewInit,
ChangeDetectorRef,
Component,
ContentChild,
ContentChildren, Directive,
ElementRef,
HostBinding,
HostListener,
Injector,
Input,
OnChanges,
OnDestroy,
QueryList,
SimpleChanges,
SkipSelf, TemplateRef,
ViewChild
} from "@angular/core";
import {Subscription} from "rxjs";
import {ngValueAccessor, ValueAccessorBase} from "../../core/form";
import {Overlay} from "@angular/cdk/overlay";
import {DropdownComponent} from "../button/dropdown.component";
import {ButtonComponent} from "../button/button.component";
/**
* Necessary directive to get a dynamic rendered option.
*
* ```html
*
*
* {{item.fieldName | date}}
*
*
* ```
*/
@Directive({
selector: '[dynamicOption]',
})
export class DynamicOptionDirective {
constructor(
public template: TemplateRef
) {
}
}
@Component({
selector: 'dui-option',
template: `
`
})
export class OptionDirective {
@Input() value: any;
@ContentChild(DynamicOptionDirective, {static: false}) dynamic?: DynamicOptionDirective;
constructor(public readonly element: ElementRef) {
}
}
class NotSelected {}
@Component({
selector: 'dui-select',
template: `
{{placeholder}}
`,
styleUrls: ['./selectbox.component.scss'],
host: {
'[attr.tabIndex]': '1',
'[class.split]': '!!button',
'[class.textured]': 'textured !== false',
'[class.small]': 'small !== false',
},
providers: [ngValueAccessor(SelectboxComponent)]
})
export class SelectboxComponent extends ValueAccessorBase implements AfterViewInit, OnDestroy, OnChanges {
@Input() placeholder: string = '';
/**
* Different textured styled.
*/
@Input() textured: boolean | '' = false;
/**
* Smaller text and height.
*/
@Input() small: boolean | '' = false;
@ContentChild(ButtonComponent, {static: false}) button?: ButtonComponent;
@ContentChildren(OptionDirective, {descendants: true}) options?: QueryList;
@ViewChild('dropdown', {static: false}) dropdown!: DropdownComponent;
public label: string = '';
public optionsValueMap = new Map();
protected changeSubscription?: Subscription;
constructor(
protected overlay: Overlay,
protected injector: Injector,
public element: ElementRef,
public readonly cd: ChangeDetectorRef,
@SkipSelf() public readonly cdParent: ChangeDetectorRef,
) {
super(injector, cd, cdParent);
this.innerValue = new NotSelected;
}
ngAfterViewInit(): void {
if (this.options) {
this.changeSubscription = this.options.changes.subscribe(() => this.updateMap());
setTimeout(() => {
this.updateMap();
});
}
}
public select(value: T) {
this.innerValue = value;
this.touch();
this.dropdown.close();
}
@HostListener('mousedown')
public onClick() {
if (this.disabled) return;
if (this.button) return;
this.dropdown.toggle();
}
ngOnChanges(changes: SimpleChanges) {
}
async writeValue(value?: T | NotSelected): Promise {
super.writeValue(value);
}
@HostBinding('class.selected')
get isSelected(): boolean {
return !(this.innerValue instanceof NotSelected);
}
protected updateMap() {
this.optionsValueMap.clear();
if (!this.options) return;
for (const option of this.options.toArray()) {
this.optionsValueMap.set(option.value, option);
}
this.cd.detectChanges();
}
ngOnDestroy(): void {
if (this.changeSubscription) {
this.changeSubscription.unsubscribe();
}
}
}