동적으로 이벤트 리스너 추가
방금 Angular 2를 엉망으로 만들기 시작했으며 누군가 요소에서 이벤트 리스너를 동적으로 추가하고 제거하는 가장 좋은 방법을 말해 줄 수 있는지 궁금합니다.
구성 요소를 설정했습니다. 템플릿의 특정 요소를 클릭하면 mousemove
동일한 템플릿의 다른 요소에 리스너를 추가하고 싶습니다 . 그런 다음 세 번째 요소를 클릭하면이 리스너를 제거하고 싶습니다.
나는 보통 Javascript를 사용하여 요소를 잡고 표준을 호출하는 방식 으로이 작업을 수행 했지만addEventListener()
더 많은 " Angular2.0 "방식 으로이 작업을 수행 해야하는지 궁금해 했습니다.
렌더러는 Angular 4.0.0-rc.1에서 더 이상 사용되지 않습니다. 아래 업데이트를 읽으십시오
angular2 방법은 사용하는 것 listen
또는 listenGlobal
에서 렌더러
예를 들어 클릭 이벤트를 구성 요소에 추가하려면 렌더러 및 ElementRef를 사용해야합니다 (이렇게하면 ViewChild 또는을 검색하는 모든 옵션을 사용할 수 있음 nativeElement
)
constructor(elementRef: ElementRef, renderer: Renderer) {
// Listen to click events in the component
renderer.listen(elementRef.nativeElement, 'click', (event) => {
// Do something with 'event'
})
);
당신은 사용할 수 있습니다 listenGlobal
당신에게 액세스 권한을 부여 할 것을 document
, body
등
renderer.listenGlobal('document', 'click', (event) => {
// Do something with 'event'
});
beta.2 이후 모두 참고 listen
하고 listenGlobal
(참조 리스너를 제거하는 기능을 반환 변경 깨는 beta.2에 대한 변경 로그에서 절). 이는 대규모 응용 프로그램에서 메모리 누수를 방지하기위한 것입니다 ( # 6686 참조 ).
따라서 동적으로 추가 한 리스너를 제거하려면 반환 된 함수를 보유 할 변수 listen
또는 listenGlobal
변수를 할당 한 다음 실행해야합니다.
// listenFunc will hold the function returned by "renderer.listen"
listenFunc: Function;
// globalListenFunc will hold the function returned by "renderer.listenGlobal"
globalListenFunc: Function;
constructor(elementRef: ElementRef, renderer: Renderer) {
// We cache the function "listen" returns
this.listenFunc = renderer.listen(elementRef.nativeElement, 'click', (event) => {
// Do something with 'event'
});
// We cache the function "listenGlobal" returns
this.globalListenFunc = renderer.listenGlobal('document', 'click', (event) => {
// Do something with 'event'
});
}
ngOnDestroy() {
// We execute both functions to remove the respectives listeners
// Removes "listen" listener
this.listenFunc();
// Removs "listenGlobal" listener
this.globalListenFunc();
}
다음 은 예제가 작동 하는 plnkr 입니다. 이 예는의 사용을 포함 listen
하고 listenGlobal
.
Angular 4.0.0-rc.1 +와 함께 RendererV2 사용 (4.0.0-rc.3 이후의 Renderer2)
25/02/2017 :
Renderer
더 이상 사용되지 않으므로 이제 사용해야합니다(아래 줄 참조). 커밋을 참조하십시오 .RendererV2
10/03/2017 :
RendererV2
로 이름이 변경되었습니다Renderer2
. 주요 변경 사항을 참조하십시오 .
RendererV2
listenGlobal
글로벌 이벤트 (문서, 본문, 창) 에는 더 이상 기능 이 없습니다 . 그것은 listen
두 기능을 모두 달성 하는 기능 만을 가지고 있습니다.
For reference, I'm copy & pasting the source code of the DOM Renderer implementation since it may change (yes, it's angular!).
listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean):
() => void {
if (typeof target === 'string') {
return <() => void>this.eventManager.addGlobalEventListener(
target, event, decoratePreventDefault(callback));
}
return <() => void>this.eventManager.addEventListener(
target, event, decoratePreventDefault(callback)) as() => void;
}
As you can see, now it verifies if we're passing a string (document, body or window), in which case it will use an internal addGlobalEventListener
function. In any other case, when we pass an element (nativeElement) it will use a simple addEventListener
To remove the listener it's the same as it was with Renderer
in angular 2.x. listen
returns a function, then call that function.
Example
// Add listeners
let global = this.renderer.listen('document', 'click', (evt) => {
console.log('Clicking the document', evt);
})
let simple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
console.log('Clicking the button', evt);
});
// Remove listeners
global();
simple();
plnkr with Angular 4.0.0-rc.1 using RendererV2
plnkr with Angular 4.0.0-rc.3 using Renderer2
I aso find this extremely confusing. as @EricMartinez points out Renderer2 listen() returns the function to remove the listener:
ƒ () { return element.removeEventListener(eventName, /** @type {?} */ (handler), false); }
If i´m adding a listener
this.listenToClick = this.renderer.listen('document', 'click', (evt) => {
alert('Clicking the document');
})
I´d expect my function to execute what i intended, not the total opposite which is remove the listener.
// I´d expect an alert('Clicking the document');
this.listenToClick();
// what you actually get is removing the listener, so nothing...
In the given scenario, It´d actually make to more sense to name it like:
// Add listeners
let unlistenGlobal = this.renderer.listen('document', 'click', (evt) => {
console.log('Clicking the document', evt);
})
let removeSimple = this.renderer.listen(this.myButton.nativeElement, 'click', (evt) => {
console.log('Clicking the button', evt);
});
There must be a good reason for this but in my opinion it´s very misleading and not intuitive.
Here's my workaround:
I created a library with Angular 6. I added a common component commonlib-header
which is used like this in an external application.
Note the serviceReference
which is the class (injected in the component constructor(public serviceReference: MyService)
that uses the commonlib-header
) that holds the stringFunctionName
method:
<commonlib-header
[logo]="{ src: 'assets/img/logo.svg', alt: 'Logo', href: '#' }"
[buttons]="[{ index: 0, innerHtml: 'Button', class: 'btn btn-primary', onClick: [serviceReference, 'stringFunctionName', ['arg1','arg2','arg3']] }]">
</common-header>
The library component is programmed like this. The dynamic event is added in the onClick(fn: any)
method:
export class HeaderComponent implements OnInit {
_buttons: Array<NavItem> = []
@Input()
set buttons(buttons: Array<any>) {
buttons.forEach(navItem => {
let _navItem = new NavItem(navItem.href, navItem.innerHtml)
_navItem.class = navItem.class
_navItem.onClick = navItem.onClick // this is the array from the component @Input properties above
this._buttons[navItem.index] = _navItem
})
}
constructor() {}
ngOnInit() {}
onClick(fn: any){
let ref = fn[0]
let fnName = fn[1]
let args = fn[2]
ref[fnName].apply(ref, args)
}
The reusable header.component.html
:
<div class="topbar-right">
<button *ngFor="let btn of _buttons"
class="{{ btn.class }}"
(click)="onClick(btn.onClick)"
[innerHTML]="btn.innerHtml | keepHtml"></button>
</div>
참고URL : https://stackoverflow.com/questions/35080387/dynamically-add-event-listener
'Programming' 카테고리의 다른 글
머티리얼 디자인 가이드 라인처럼 보이는 SearchView 생성 (0) | 2020.06.28 |
---|---|
JSF 1.2에서 JSF 2.0으로 마이그레이션 (0) | 2020.06.27 |
Windows의 원격 컴퓨터에서 서비스를 다시 시작하려면 어떻게합니까? (0) | 2020.06.27 |
Android 에뮬레이터의 스토리지를 늘리는 방법은 무엇입니까? (0) | 2020.06.27 |
delete []는 그것이 배열임을 어떻게 알 수 있습니까? (0) | 2020.06.27 |