Typescript-händelsebindning och avbindning


Jag ställde den här frågan för en tid sedan om att delegera jQuery-händelser till händelsehanteringsmetoder i en TypeScript-klass. Svaret var att använda följande mönster

public class LoginDialog { 
     ...
     constructor() { 
        //this.open = this.OpenHandler; //Incorrect way
        this.open = (event: Event, ui: DialogUIParams) => {  //Correct way
             this.OpenHandler(this, event, ui);
        }; 
        ...
     }

     public OpenHandler(context: LoginDialog, event: Event, ui: DialogUIParams) { 
           //Use context as "this"
     } 
     ...
 } 

Men nu är jag i en liknande situation där jag behöver ta bort hanteraren vid någon tidpunkt i framtiden men inte kan på grund av den anonyma funktionen:

public class LoginDialog { 
     ...
     constructor() { 
        this.open = (event: Event, ui: DialogUIParams) => {  
             this.OpenHandler(this, event, ui);
        }; 
        this.close = (event: Event, ui: DialogUIParams) => {
             this.CloseHandler(this, event, ui);
        }
        ...
     }

     public OpenHandler(context: LoginDialog, event: Event, ui: DialogUIParams) { 
           $(window).on("scroll", () => { context.ScrollHandler(context); });
           //$(window).on("scroll", context.ScrollHandler(context)); //Never gets called
           //$(window).on("scroll", context.ScrollHandler); //this = window
     } 

     public CloseHandler(context: LoginDialog, event: Event, ui: DialogUIParams) { 
           $(window).off("scroll", () => { context.ScrollHandler(context); }); //Does not remove
     } 

     public ScrollHandler(context: Interfaces.IBaseDialog) { 
           context.jQueryDialog.dialog("option", "position", "center");
           ...
     }
     ...
 } 

I det här fallet, utan pilsyntaxen i on-bindningen, blir min ResizeOrScrollHandler aldrig kallad, men med den kan jag inte ta bort eventhanteraren i CloseHandler

Svar #1

För att sammanfatta ditt problem, försöker du använda jQuery för att koppla (och koppla bort) en händelse på ett DOM-element, men du vill att händelsehanterarens 'this'-kontext ska peka på klassen som innehåller händelsehanteraren.

Det finns flera sätt att lösa detta.

Först kan du använda jQuery.proxy

class LoginDialog {

   public OpenHandler(context: LoginDialog, event: Event, ui: DialogUIParams) { 
      $(window).on("scroll", $.proxy(context.ScrollHandler, context));
   }    

   public CloseHandler(context: LoginDialog, event: Event, ui: DialogUIParams) {
      $(window).off("scroll", context.ScrollHandler);
   }
}

Ett annat alternativ skulle vara att använda RxJS, vilket gör att du kan behandla händelser som borttagbara objekt:

var scrollSubscription = $(window)
     .onAsObservable("scroll")
     .subscribe(() => console.log("this == the containing class!"));
...
// When we're done, just call .dispose.
scrollSubscription.dispose();

Ha kul.

Relaterade artiklar