Подтвердить что ты не робот

Как настроить фокус на другой вход?

Мне нужно иметь возможность переключать фокус на элемент ввода, когда происходит какое-то событие. Как это сделать в Angular 2?

Например:

<input (keyUp)="processKeyUp($event)"/>
<input (focusme)="alert('i am focused')"/>

Я хочу сфокусировать второе поле ввода, когда в первом нажата определенная клавиша. Я думаю, что мне нужно использовать настраиваемое событие (focusme в фрагменте), но я не знаю, где и как его объявить, и использовать ли для него аннотацию @Directive или включить его определение в компонент как-то. Короче говоря, я в тупике.

UPDATE

Забыл упомянуть, я знаю, что могу это сделать, используя локальные переменные в html, но я хочу иметь возможность сделать это из компонента, и я хочу иметь возможность выполнять сложную логику при запуске focusme чтобы контролирующие его прослушивание могли определить, предназначено ли оно для них или нет. Спасибо!

4b9b3361

Ответ 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 />