Skip to content

Instantly share code, notes, and snippets.

@fireonmac
Created June 30, 2023 10:48
Show Gist options
  • Save fireonmac/21d843b78984097b6df70ff23932ba1c to your computer and use it in GitHub Desktop.
Save fireonmac/21d843b78984097b6df70ff23932ba1c to your computer and use it in GitHub Desktop.
import {
AfterViewInit,
Directive,
ElementRef,
EventEmitter,
Input,
OnDestroy,
Output,
Renderer2,
} from '@angular/core';
import { filter, fromEvent, map, Subject, takeUntil } from 'rxjs';
export type FileInputAttributes = {
name?: string;
accept?: string;
placeholder?: string;
id?: string;
disabled?: boolean;
readonly?: boolean;
multiple?: boolean;
change?: (event: Event) => void;
};
@Directive({
standalone: true,
selector: '[appFileInput]',
})
export class FileInputDirective implements OnDestroy, AfterViewInit {
@Input() appFileInput: FileInputAttributes = {};
@Output() change = new EventEmitter<Event>();
private destroy$ = new Subject();
input: HTMLInputElement = this.renderer.createElement('input');
get files() {
return this.input.files as FileList;
}
files$ = fromEvent(this.input, 'change').pipe(
filter(() => !!this.input?.files),
map(() => this.input.files),
takeUntil(this.destroy$)
);
ngOnDestroy() {
// DOM에서 제거
this.input.remove();
this.destroy$.next(null);
this.destroy$.complete();
}
ngAfterViewInit() {
// 속성 설정
this.renderer.setAttribute(this.input, 'type', 'file');
this.renderer.setAttribute(this.input, 'style', 'display: none');
Object.entries(this.appFileInput).forEach(([key, value]) => {
typeof value === 'string' &&
this.renderer.setAttribute(this.input, key, value);
typeof value === 'boolean' &&
this.renderer.setAttribute(this.input, key, value.toString());
});
// 클릭 시 파일 선택창 열기
fromEvent(this.elementRef.nativeElement, 'click')
.pipe(takeUntil(this.destroy$))
.subscribe(() => this.input.click());
fromEvent(this.input, 'change')
.pipe(takeUntil(this.destroy$))
.subscribe((ev) => this.change.emit(ev));
// DOM 노드에 삽입
this.renderer.appendChild(document.body, this.input);
}
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment