page example change angular

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 usar RendererV2 (ver la línea a continuación). Ver el commit .

  • 10/03/2017 : RendererV2 pasó a llamarse Renderer2 . 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.