kamilk kamilk - 4 months ago 29
TypeScript Question

Output part of two-way binding doesn't work for custom directive

I am trying to implement a directive with a property that would support a two-way binding like this:

. A component could set its
property to true to focus on an element but the variable would get reverted to false once the element loses focus.

I've read (here and here) that the key to implementing this kind of binding is having two properties for
named the same but with the output one suffixed with
. So this is my implementation so far (in TypeScript):

selector: '[appfocused]'
export class FocusedDirective implements OnChanges, AfterViewInit {
focused: boolean;

focusedChange: EventEmitter<boolean> = new EventEmitter();

constructor(private elementRef: ElementRef, private renderer: Renderer) { }

ngAfterViewInit() {
this.renderer.listen(this.elementRef.nativeElement, 'blur', () => {

ngOnChanges() {
if (this.focused) {
setTimeout(() => {
}, 0);

private setFocused(value: boolean) {
this.focused = value;
console.log('focused set to ' + value);

The input property works fine but I can't get the output property to work. Thanks to the
call, I know the
line is being hit but it has no effect on the value the property is bound to.

Here is a working example (plunker). It includes a dummy component which displays and sets the value of the

selector: 'my-app',
template: `
<textarea [(appfocused)]="isFocused"></textarea>
<a (click)="focus()" href="#">Focus</a>
export class App {
isFocused = false;

focus() {
this.isFocused = true;

Pressing the Focus link focuses on the
as expected. However, clicking out of it does not reset the
variable. Pressing the link again has no effect - the value of
was already true so Angular doesn't detect any changes.

What am I missing?


As the article you've mentioned stated, for the two-way binding shorthand syntax to work the output's name has to be the same as the input plus the "Change" suffix.

So you're almost there - you just have to name the @Output() properly: not "appfocused", but "appfocusedChange" instead:

focusedChange: EventEmitter<boolean> = new EventEmitter();