Как настроить фокус на другой вход?
Мне нужно иметь возможность переключать фокус на элемент ввода, когда происходит какое-то событие. Как это сделать в Angular 2?
Например:
<input (keyUp)="processKeyUp($event)"/>
<input (focusme)="alert('i am focused')"/>
Я хочу сфокусировать второе поле ввода, когда в первом нажата определенная клавиша. Я думаю, что мне нужно использовать настраиваемое событие (focusme
в фрагменте), но я не знаю, где и как его объявить, и использовать ли для него аннотацию @Directive
или включить его определение в компонент как-то. Короче говоря, я в тупике.
UPDATE
Забыл упомянуть, я знаю, что могу это сделать, используя локальные переменные в html, но я хочу иметь возможность сделать это из компонента, и я хочу иметь возможность выполнять сложную логику при запуске focusme
чтобы контролирующие его прослушивание могли определить, предназначено ли оно для них или нет.
Спасибо!
Ответы
Ответ 1
Вы можете сделать это, просто передав второй вход в качестве переменной в первую.
Например
HTML
<!-- We pass focusable as a parameter to the processKeyUp function -->
<input (keyup)="processKeyUp($event, focusable)"/>
<!-- With #focusable we are creating a variable which references to the input -->
<input #focusable />
Позже в js/ts
@Component({
selector: 'plunker-app'
})
@View({
templateUrl: 'main.html'
})
class PlunkerApp {
constructor() {
}
processKeyUp(e, el) {
if(e.keyCode == 65) { // press A
el.focus();
}
}
}
el - это необработанный элемент, поэтому вы можете использовать на нем чистый javascript.
Здесь plnkr, чтобы вы могли видеть его работу.
Надеюсь, это поможет.
Ответ 2
Для манипуляции с элементами DOM всегда старайтесь использовать директивы. В этом случае вы можете написать простую директиву.
Для доступа к DOM из директивы мы можем ввести ссылку на наш элемент DOM нашего узла конструктором ElementRef.
constructor(@Inject(ElementRef) private element: ElementRef) {}
Для обнаружения изменений привязанного значения мы можем использовать метод ngOnChanges livecycle.
protected ngOnChanges() {}
Все остальное просто.
Простое решение
// Simple 'focus' Directive
import {Directive, Input, ElementRef} from 'angular2/core';
@Directive({
selector: '[focus]'
})
class FocusDirective {
@Input()
focus:boolean;
constructor(@Inject(ElementRef) private element: ElementRef) {}
protected ngOnChanges() {
this.element.nativeElement.focus();
}
}
// Usage
@Component({
selector : 'app',
template : `
<input [focus]="inputFocused" type="text">
<button (click)="moveFocus()">Move Focus</button>
`,
directives: [FocusDirective]
})
export class App {
private inputFocused = false;
moveFocus() {
this.inputFocused = true;
// we need this because nothing will
// happens on next method call,
// ngOnChanges in directive is only called if value is changed,
// so we have to reset this value in async way,
// this is ugly but works
setTimeout(() => {this.inputFocused = false});
}
}
Решение с EventEmitter
Чтобы решить проблему с помощью setTimeout (() = > {this.inputFocused = false}); Мы можем привязать нашу директиву к источнику событий - EventEmitter или Observable. Ниже приведен пример использования EventEmitter.
// Directive
import {Directive, EventEmitter, Input, ElementRef} from 'angular2/core';
@Directive({
selector: '[focus]'
})
class FocusDirective {
private focusEmitterSubscription;
// Now we expect EventEmitter as binded value
@Input('focus')
set focus(focusEmitter: EventEmitter) {
if(this.focusEmitterSubscription) {
this.focusEmitterSubscription.unsubscribe();
}
this.focusEmitterSubscription = focusEmitter.subscribe(
(()=> this.element.nativeElement.focus()).bind(this))
}
constructor(@Inject(ElementRef) private element: ElementRef) {}
}
// Usage
@Component({
selector : 'app',
template : `
<input [focus]="inputFocused" type="text">
<button (click)="moveFocus()">Move Focus</button>
`,
directives: [FocusDirective]
})
class App {
private inputFocused = new EventEmitter();
moveFocus() {
this.inputFocused.emit(null);
}
}
Оба решения решают вашу проблему, но во-вторых, имеют немного лучшую производительность и выглядят лучше.
Ответ 3
На самом деле вам не нужно писать какой-либо код TS для этого (я использую один из других примеров ответов):
<input (keyup.enter)="focusable.focus()"/>
<input #focusable />