angular - example - Agregue dinĂ¡micamente escucha de eventos
page title angular 4 (3)
Estoy empezando a perder el tiempo con Angular 2 y me pregunto si alguien puede decirme la mejor manera de agregar y eliminar dinámicamente los oyentes de eventos de los elementos.
Tengo un componente configurado.
Cuando se hace clic en cierto elemento de la plantilla, quiero agregar un oyente para
mousemove
a otro elemento de la misma plantilla.
Luego quiero eliminar este oyente cuando se hace clic en un tercer elemento.
De alguna manera conseguí que esto funcionara simplemente usando Javascript simple para capturar los elementos y luego llamando al
addEventListener()
estándar
addEventListener()
pero me preguntaba si había una forma más "
Angular2.0
" de hacer esto que debería estar investigando.
El procesador ha quedado en desuso en Angular 4.0.0-rc.1, lea la actualización a continuación
La
forma angular2
es usar
listen
o
listenGlobal
de
Renderer
Por ejemplo, si desea agregar un evento de clic a un Componente, debe usar Renderer y ElementRef (esto también le da la opción de usar ViewChild, o cualquier cosa que recupere el elemento
nativeElement
)
constructor(elementRef: ElementRef, renderer: Renderer) {
// Listen to click events in the component
renderer.listen(elementRef.nativeElement, ''click'', (event) => {
// Do something with ''event''
})
);
Puede usar
listenGlobal
que le dará acceso a
document
,
body
, etc.
renderer.listenGlobal(''document'', ''click'', (event) => {
// Do something with ''event''
});
Tenga en cuenta que desde beta.2,
listen
y
listenGlobal
devuelven una función para eliminar el oyente (consulte la sección de cambios de ruptura del registro de cambios para beta.2).
Esto es para evitar pérdidas de memoria en grandes aplicaciones (ver
#6686
).
Entonces, para eliminar el oyente que agregamos dinámicamente, debemos asignar
listen
o
listenGlobal
a una variable que contendrá la función devuelta, y luego la ejecutamos.
// 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();
}
Aquí hay un
plnkr
con un ejemplo funcionando.
El ejemplo contiene el uso de
listen
y
listenGlobal
.
Uso de RendererV2 con Angular 4.0.0-rc.1 + (Renderer2 desde 4.0.0-rc.3)
-
25/02/2017 :
Renderer
ha quedado en desuso, ahora deberíamos usarRendererV2
-
10/03/2017 :
RendererV2
pasó a llamarseRenderer2
. Ver los cambios de última hora .
RendererV2
ya no tiene la función
listenGlobal
para eventos globales (documento, cuerpo, ventana).
Solo tiene una función de
listen
que logra ambas funcionalidades.
Como referencia, copio y pego el código fuente de la implementación del DOM Renderer ya que puede cambiar (¡sí, es 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;
}
Como puede ver, ahora verifica si estamos pasando una cadena (documento, cuerpo o ventana), en cuyo caso utilizará una función interna
addGlobalEventListener
.
En cualquier otro caso, cuando pasamos un elemento (nativeElement) usará un simple
addEventListener
Para eliminar el oyente es lo mismo que con
Renderer
en angular 2.x.
listen
devuelve una función, luego llama a esa función.
Ejemplo
// 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 con Angular 4.0.0-rc.1 usando RendererV2
plnkr con Angular 4.0.0-rc.3 usando Renderer2
Aquí está mi solución:
commonlib-header
una biblioteca con Angular 6.
commonlib-header
un componente común
commonlib-header
que se usa así en una aplicación externa.
Tenga en cuenta la
serviceReference
que es la clase (inyectada en el
constructor(public serviceReference: MyService)
componentes
constructor(public serviceReference: MyService)
que usa el
commonlib-header
) que contiene el método
stringFunctionName
:
<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>
El componente de la biblioteca se programa así.
El evento dinámico se agrega en el método
onClick(fn: any)
:
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)
}
El
header.component.html
reutilizable.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>
Esto me parece extremadamente confuso. como @EricMartinez señala Renderer2 listen () devuelve la función para eliminar el oyente:
ƒ () { return element.removeEventListener(eventName, /** @type {?} */ (handler), false); }
Si estoy agregando un oyente
this.listenToClick = this.renderer.listen(''document'', ''click'', (evt) => {
alert(''Clicking the document'');
})
Esperaría que mi función ejecute lo que pretendía, no el opuesto total que es eliminar el oyente.
// I´d expect an alert(''Clicking the document'');
this.listenToClick();
// what you actually get is removing the listener, so nothing...
En el escenario dado, en realidad tendría más sentido nombrarlo así:
// 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);
});
Debe haber una buena razón para esto, pero en mi opinión es muy engañoso y no intuitivo.