Concentre-se no elemento de input recém-adicionado

Eu tenho um novo aplicativo Angular 2 com uma lista de checkboxs de input. Quando o usuário pressiona a tecla de retorno, eu adiciono uma nova checkbox de input imediatamente após a que estão editando no momento. Ou melhor, eu (de forma assíncrona) adiciono uma nova input ao array no modelo, o que faz com que o Angular 2 gere automaticamente uma nova checkbox de input em um futuro próximo.

Como posso fazer com que o foco de input mude para o elemento recém-adicionado automaticamente?

[edit] Como alternativa, obtenho uma referência ao object de modelo que está causando a geração do DOM. A partir do código do componente, existe uma maneira de procurar um elemento DOM que represente um determinado object de modelo?

[edit] Aqui está o meu código para fazer isso funcionar. Espero que isso seja ofensivo o suficiente para alguns desenvolvedores Angular 2 para incentivar uma resposta 🙂

app.WordComponent = ng.core .Component({ selector: 'word-editor', template:'', styles:[ '' ], properties:[ 'list:list', 'word:word' ] }) .Class({ constructor:[ function() { } ], keydown:function(e) { if(e.which == 13) { var ul = e.target.parentNode.parentNode.parentNode; var childCount = ul.childNodes.length; this.list.addWord("").then(function(word) { var interval = setInterval(function() { if(childCount < ul.childNodes.length) { ul.lastChild.querySelector('input').focus(); clearInterval(interval); } }, 1); }); } } }); 

Se eu tiver permissão para fazer isso, vou participar da resposta do @Sasxa e modificá-la para torná-la mais parecida com o que você está procurando.

Algumas mudanças

  • Vou usar um ngFor so angular2 adiciona a nova input em vez de fazê-lo sozinho. O principal objective é apenas fazer com que o angular2 itere sobre ele.
  • Em vez de ViewChild , vou usar ViewChildren que retorna um QueryList que possui uma propriedade changes . Essa propriedade é um Observable e retorna os elementos depois que eles foram alterados.

Como no ES5, não temos decoradores, temos que usar a propriedade queries para usar ViewChildren

Componente

 Component({ selector: 'cmp', template : ` 
// We use a variable so we can query the items with it
`, queries : { vc : new ng.core.ViewChildren('input') } })

Concentre-se no último elemento.

 ngAfterViewInit: function() { this.vc.changes.subscribe(elements => { elements.last.nativeElement.focus(); }); } 

Como eu disse antes, ViewChildren retorna uma propriedade QueryList que contém changes . Quando nos inscrevemos nele toda vez que ele for alterado, ele retornará a lista de elementos. Os elements lista contém uma last propriedade (entre outras) que neste caso retorna o último elemento, nós usamos nativeElement nele e finalmente focus()

Adicionar elementos de input Isso é para pure convenince, o array de inputs não tem propósito real mais do que redesenhar o ngFor .

 add: function(key) { if(key.which == 13) { // See plnkr for "this.inputs" usage this.inputs.push(this.inputs.length+1); } } 

Nós empurramos um item fictício no array para que ele seja redesenhado.

Exemplo usando o ES5: http://plnkr.co/edit/DvtkfiTjmACVhn5tHGex

Exemplo usando ES6 / TS: http://plnkr.co/edit/93TgbzfPCTxwvgQru2d0?p=preview

Atualização 29/03/2016

O tempo passou, as coisas foram esclarecidas e sempre há boas práticas para aprender / ensinar. Eu simplifiquei esta resposta mudando algumas coisas

  • Em vez de usar @ViewChildren e subscrevê-lo, fiz uma diretiva que será instatada toda vez que uma nova input for criada
  • Estou usando o Renderer para tornar o WebWorker seguro. A resposta original acessa focus() diretamente no nativeElement que é desencorajado.
  • Agora eu ouço o keydown.enter que simplifica o evento de desativação da tecla, não preciso verificar which valor.

Ao ponto. O componente se parece com (simplificado, código completo nos plnkrs abaixo)

 @Component({ template: ``, }) add() { this.inputs.push(this.inputs.length+1); } 

E a diretiva

 @Directive({ selector : 'input' }) class MyInput { constructor(public renderer: Renderer, public elementRef: ElementRef) {} ngOnInit() { this.renderer.invokeElementMethod( this.elementRef.nativeElement, 'focus', []); } } 

Como você pode ver, estou chamando invokeElementMethod para acionar o focus no elemento, em vez de acessá-lo diretamente.

Esta versão é muito mais limpa e segura que a original.

plnkrs atualizado para beta 12

Exemplo usando ES5: http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr

Exemplo usando ES6 / TS: http://plnkr.co/edit/em18uMUxD84Z3CK53RRe

Atualizar 2018

invokeElementMethod foi reprovado. Use Renderer2 em vez de Renderer.

Dê um id ao seu elemento e você pode usar selectRootElement :

 this.renderer2.selectRootElement('#myInput').focus(); 

Dê uma olhada no ViewChild , aqui está um exemplo . Isso pode ser o que você está procurando:

 import {Component, ViewChild} from 'angular2/core' @Component({ selector: 'my-app', providers: [], template: ` 
`, directives: [] }) export class App { @ViewChild('name') vc: ElementRef; ngAfterViewInit() { this.vc.nativeElement.focus(); } }

Com o código angular embutido, concentre-se após a pintura condicional:

      {{taskEditText.focus()}}  

Você pode implementar uma diretiva de texto de input simples, de modo que, sempre que uma nova input for criada, ela se concentre automaticamente. O método focus() é chamado dentro do gancho do ciclo de vida do componente ngAfterViewInit() depois que a visualização é totalmente inicializada.

 @Directive({ selector: 'input[type=text]' }) export class FocusInput implements AfterViewInit { private firstTime: bool = true; constructor(public elem: ElementRef) { } ngAfterViewInit() { if (this.firstTime) { this.elem.nativeElement.focus(); this.firstTime = false; } } } 

Use a diretiva FocusInput no seu componente:

 @Component({ selector: 'app', directives: [FocusInput], template: `{{words |json}}` }) export class AppComponent { words: Word[] = []; constructor() { this.addNewWord(); } addNewWord() { this.words.push(new Word()); } } 

Observe o seguinte:

  1. O evento (keyup.enter) é usado para detectar quando a tecla é pressionada
  2. ngFor é usado para repetir o elemento de input para cada palavra da matriz de words
  3. last é um booleano ligado a uma variável local que é verdadeira quando a input é a última
  4. O evento de chave está vinculado à last ? addNewWord() : 0 expressão last ? addNewWord() : 0 last ? addNewWord() : 0 . Isso garante que um novo campo de input seja adicionado somente quando a tecla é pressionada a partir da última input.

Demo Plnkr

Para priorizar qual elemento receberá o foco ao inicializar várias diretivas no mesmo ciclo, use:

Directiva:

 @Directive({ selector: '[focusOnInit]' }) export class FocusOnInitDirective implements OnInit, AfterViewInit { @Input('focusOnInit') priority: number = 0; static instances: FocusOnInitDirective[] = []; constructor(public renderer: Renderer, public elementRef: ElementRef) { } ngOnInit(): void { FocusOnInitDirective.instances.push(this) } ngAfterViewInit(): void { setTimeout(() => { FocusOnInitDirective.instances.splice(FocusOnInitDirective.instances.indexOf(this), 1); }); if (FocusOnInitDirective.instances.every((i) => this.priority >= i.priority)) { this.renderer.invokeElementMethod( this.elementRef.nativeElement, 'focus', []); } } } 

Uso:

  

https://plnkr.co/edit/T9VDPIWrVSZ6MpXCdlXF