Skip to content

Commit

Permalink
fix(HostListener): invoke listeners within a digest
Browse files Browse the repository at this point in the history
Fixes #11
  • Loading branch information
jbedard committed Feb 23, 2017
1 parent 2db5fe0 commit cc92972
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 5 deletions.
55 changes: 55 additions & 0 deletions src/facade.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,61 @@ describe("facade", function() {
expect(bar).toHaveBeenCalled();
});

it("should invoke the expression within a digest", function() {
const foo = jasmine.createSpy("foo event callback");

let phase;
@Component({
selector: "comp"
})
class Comp {
constructor(@Inject("$rootScope") public $rootScope) {}

@HostListener("asdf")
adsf() {
phase = this.$rootScope.$$phase;
}
}

@NgModule({id: "compMod", declarations: [Comp]})
class Mod {}

const {$dom} = bootstrapAndCompile("compMod", "<comp>");

expect(phase).toBeUndefined();
$dom.triggerHandler("asdf");
expect(phase).toBe("$apply");
});

it("should support DOM events triggered while already in a digest", function() {
const foo = jasmine.createSpy("foo event callback");

@Component({
selector: "comp"
})
class Comp {
constructor(@Inject("$element") private $element) {}
@HostListener("asdf")
adsf() {
foo.apply(this, arguments);
}

@HostListener("first")
first() {
this.$element.triggerHandler("asdf");
}
}

@NgModule({id: "compMod", declarations: [Comp]})
class Mod {}

const {$dom} = bootstrapAndCompile("compMod", "<comp>");

expect(foo).not.toHaveBeenCalled();
$dom.triggerHandler("first");
expect(foo).toHaveBeenCalled();
});

it("should pass arguments specified in @HostListener('asdf', [...args])", function() {
const foo = jasmine.createSpy("foo event callback");

Expand Down
16 changes: 11 additions & 5 deletions src/facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,18 +434,24 @@ export class EventEmitter<T> {
//https://github.com/angular/angular/blob/2.4.5/modules/%40angular/core/src/metadata/directives.ts#L1005-L1017
export function HostListener(eventType: string, args: string[] = []): MethodDecorator {
return function(targetPrototype: Object, propertyKey: string): void {
function HostListenerSetup($element: JQuery, $parse: angular.IParseService, $injector: angular.auto.IInjectorService): void {
function HostListenerSetup($element: JQuery, $parse: angular.IParseService, $rootScope: angular.IScope): void {
//Parse the listener arguments on component initialization
const argExps = args.map((s) => $parse(s));

$element.on(eventType, ($event) => {
//Invoke each argument expression using only the $event local
$element.on(eventType, ($event: BaseJQueryEventObject) => {
//Invoke each argument expression specifying the $event local
const argValues = argExps.map((argExp) => argExp({$event}));
const invokeListener = () => this[propertyKey](...argValues);

this[propertyKey](...argValues);
if (!$rootScope.$$phase) {
$rootScope.$apply(invokeListener);
}
else {
invokeListener();
}
});
}
HostListenerSetup.$inject = ["$element", "$parse", "$injector"];
HostListenerSetup.$inject = ["$element", "$parse", "$rootScope"];

addPreLink(targetPrototype, HostListenerSetup);
};
Expand Down

0 comments on commit cc92972

Please sign in to comment.