网站搜索

angular - 双向绑定的输出部分在自定义指令中不起作用


我正在尝试实现一个指令,该指令具有一个属性,可以支持这样的双向绑定:[(appfocused)]="isFocused"。组件可以将它的isFocused属性设置为true以将焦点放在某个元素上,但一旦元素失去焦点,该变量就会被重置为false。

我已经阅读过(这里和这里)关于实现这种绑定的关键是为 @Input 和 @Output 设置两个同名的属性,但输出属性的名称要加上 Change 后缀。所以这是我目前的实现(使用 TypeScript):

@Directive({
    selector: '[appfocused]'
})
export class FocusedDirective implements OnChanges, AfterViewInit {
    @Input('appfocused')
    focused: boolean;

    @Output('appfocused')
    focusedChange: EventEmitter<boolean> = new EventEmitter();

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

    ngAfterViewInit() {
        this.renderer.listen(this.elementRef.nativeElement, 'blur', () => {
            this.setFocused(false);
        });
    }

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

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

输入属性工作正常,但我无法让输出属性工作。多亏了 console.log 调用,我知道 focusedChange.emit() 这一行被执行了,但它对绑定该属性的值没有任何影响。

这是一个可运行的示例(plunker)。它包括一个虚拟组件,该组件显示并设置isFocused属性的值:

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

  focus() {
    this.isFocused = true;
  }
}

按下 Focus 链接会按预期将焦点集中到 textarea 上。然而,点击它以外的地方不会重置 isFocused 变量。再次按下该链接没有效果——isFocused 的值已经为 true,因此 Angular 没有检测到任何变化。

我漏掉了什么?

答案#1

正如你提到的文章所述,要让双向绑定的简写语法生效,输出的名称必须与输入相同加上“Change”后缀。

所以你几乎完成了——你只需要正确命名 @Output():不要用“appfocused”,而是用“appfocusedChange”:

@Output('appfocusedChange')
focusedChange: EventEmitter<boolean> = new EventEmitter();