1. ホーム
  2. angular

[解決済み] 新たに追加された入力要素に注目

2023-08-29 10:59:25

質問

新しいAngular 2のアプリに input ボックスのリストがあります。ユーザーがリターンキーを押したとき、私は新しい input ボックスを追加します。というか、(非同期に)モデル内の配列に新しいエントリーを追加し、それによってAngular 2が自動的に新しい input ボックスが自動的に生成されます。

どうすれば input が自動的に追加されるようにするにはどうしたらよいでしょうか?

EDIT 1:

あるいは、DOMを生成する原因となっているモデルオブジェクトへの参照を取得することができます。コンポーネントコードから、特定のモデルオブジェクトを表すDOM要素を検索する方法はありますか?

EDIT 2:

これは、これを動作させるための私のコードです。これがAngular 2の開発者にとって十分に不快なものであり、返信を促すものであることを願っています:-)

app.WordComponent = ng.core
    .Component({
        selector: 'word-editor',
        template:'<input type="text" [value]="word.word" (input)="word.update($event.target.value)" (keydown)="keydown($event)"/>',
        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);
                });
            }
        }
    });

どのように解決するのですか?

もし許されるなら、@Sasxaの回答の一部を取り出して、あなたが探しているものに近づけるように修正します。

いくつかの変更点

  • を使うことにします。 ngFor を使うことで、自分でやる代わりにangular2が新しい入力を追加するようにします。主な目的は、angular2がそれを反復処理するようにするだけです。
  • の代わりに ViewChild を使うことにします。 ViewChildren を返すもので クエリリスト を持ち changes というプロパティがあります。このプロパティはObservableであり、変更後の要素を返します。

ES5ではデコレータがないため、このプロパティは queries プロパティを使って ViewChildren

コンポーネント

Component({
    selector: 'cmp',
    template : `
        <div>
            // We use a variable so we can query the items with it
            <input #input (keydown)="add($event)" *ngFor="#input of inputs">
        </div>
    `,
    queries : {
        vc : new ng.core.ViewChildren('input')
    }
})

フォーカス を最後の要素に設定します。

ngAfterViewInit: function() {

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

}

先ほど言ったように、ViewChildren は QueryList を返し、その中には changes プロパティを含むQueryListを返します。これをサブスクライブすると、変更されるたびに要素のリストが返されます。リスト elements には last プロパティがあり、この場合最後の要素を返すので、ここでは nativeElement を使い、最後に focus()

input要素の追加 これは純粋に利便性のためで、入力配列には ngFor .

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

を押しています。 ダミー を押し、再描画するようにします。

ES5を使った例。 http://plnkr.co/edit/DvtkfiTjmACVhn5tHGex

ES6/TSを使用した例. http://plnkr.co/edit/93TgbzfPCTxwvgQru2d0?p=preview

2016年03月29日更新

時間が経過し、物事が明確になり、学ぶべき/教えるべきベストプラクティスが常に存在します。私はいくつかの点を変更することで、この回答を簡素化しました。

  • を使用する代わりに @ViewChildren を使って購読する代わりに、新しい入力が作成されるたびに インスタンス化されるディレクティブを作りました。
  • を使っています。 Renderer を使ってWebWorkerの安全性を高めています。オリジナルの回答は focus() に直接アクセスします。 nativeElement というのはお勧めしません。
  • 今、私が聴いているのは keydown.enter を聞くようになり、キーダウンイベントが単純化されました。 which の値をチェックする必要がありません。

要点に コンポーネントは以下のようになります(簡略化、フルコードは以下のplnkrsにあります)。

@Component({
  template: `<input (keydown.enter)="add()" *ngFor="#input of inputs">`,
})

add() {
    this.inputs.push(this.inputs.length+1);
}

そして、ディレクティブは

@Directive({
  selector : 'input'
})
class MyInput {
  constructor(public renderer: Renderer, public elementRef: ElementRef) {}

  ngOnInit() {
    this.renderer.invokeElementMethod(
      this.elementRef.nativeElement, 'focus', []);
  }
}

見ての通り、私は invokeElementMethod を呼び出して、トリガーとして focus をトリガーします。

このバージョンは、オリジナルのものよりずっとクリーンで安全です。

plnkrs がベータ12に更新されました。

ES5を使った例: http://plnkr.co/edit/EpoJvff8KtwXRnXZJ4Rr

ES6/TSを使用した例. http://plnkr.co/edit/em18uMUxD84Z3CK53RRe

2018年最新情報

invokeElementMethod は非推奨です。Rendererの代わりにRenderer2を使ってください。

要素にidをつけると selectRootElement :

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