web-dev-qa-db-ja.com

angular2 ngModel / ngValue選択オプションオブジェクト-異なるインスタンス間の同等性

この質問のフレーバーは、リリース前にAngular2のさまざまなバージョンで何度も尋ねられています。ただし、ここでのプランクでは、目的の動作(回避したい回避策の省略)を生成するものはまだ見つかりません。 Select Object Problems

私のフォーム選択には、[(ngModel)]を介したオブジェクトへの2方向のバインディングがあり、次に 'option'が* ngForを介して類似オブジェクトのリストに対して生成されます(すべてIDで区別されます)。私の研究では、Angular2がJavaScriptオブジェクト等価を(インスタンスごとに)使用することが何度か言及されているため、同じインスタンスを持たないバインドモデル内のオブジェクトはリストに一致しません。したがって、「選択された」アイテムとして表示されず、「双方向」データバインディングが破壊されます。

ただし、これらのインスタンスが一致する方法を定義したいと思います。インターネット上で浮かんでいるように見えるいくつかの解決策が試みられましたが、私は小さな断片を見逃しているか、正しく実装されていません。

避けたいオプション:

  • NgModelのオブジェクト(つまり、id)以外の何かにバインドします。 ngValueは私が利用したい素晴らしい助けです
  • 変更ハンドラーによる回避策
  • インスタンスを強制的に一致させます(データサービスからオブジェクトを取得していますが、一致するようにすべてを再定義したくありません...これは不必要なリソースの浪費のようです)

理想的には(これは解決策があるいくつかの場所で可能な限り議論されているようです-私の場合は解決策は不十分です)、ngModelがオブジェクトインスタンスの等価性の代わりに使用する等価性の標準を定義することが可能です。

つまり、以下の最新の試みでは、h.id == a.idが属性「選択」を定義しています。私が理解していないのは、この「選択された」属性がレンダリングされない理由です-ngModelによって何らかの形でブロックされていますか? HTMLでselected = 'true'を手動で設定すると修正されるようですが、[attr.selected]またはng-reflect-selected = 'true'属性を構築する他のバリアントを使用して生成することは、トリックを実行しないようです。

<div *ngFor='let a of activePerson.hobbyList ; let i=index; trackBy:a?.id'>

    <label for='personHobbies'>Hobby:</label>
    <select id='personHobbies' class='form-control'
        name='personHobbies' [(ngModel)]='activePerson.hobbyList[i]' #name='ngModel'>

        <option *ngFor='let h of hobbyListSelect; trackBy:h?.id' 
            [ngValue]='h' 
            [attr.selected]='h.id == a.id ? true : null'
        >
        {{h.name}}
        </option>
    </select>
</div>

私が試したいくつかのこと:

  • trackBy
  • [selected] =、selected = {{}}、および[attr.selected]へのバインド(これは近いようです)

私は次のようなHTMLのレンダリングに成功しました。

<select ...>
    <option selected='true'>Selected</option>
    <option selected='false'>Not Selected</option>
    <!-- and variants, excluding with selected=null-->
</select>

しかし、オブジェクトインスタンスが異なる場合、選択された値はまだありません。また、ユーザーが値を選択したときに、選択された値を記録しているHTMLまたはCSSの要素(ngModelの処理方法、および処理のための他のオプション)を見つけようと試みました。

どんな助けも大歓迎です。目標は、「変更」ボタンを取得して基礎となるモデルを変更し、それに応じて選択ボックスを更新することです。「hobbyList」に焦点を当てています。 FirefoxとChromeで試しました。ありがとう!

18
cole

@Klinkiあたり

現在、angular 2には簡単な解決策はありませんが、angular 4では、ベータ6以降、 compareWith - https://github.com/angular/angular/pull/13349 を参照

提案されたケースの使用法を説明するために( plunkを参照 ):

<div *ngFor='let a of activePerson.hobbyList ; let i=index;'>

        <label for='personHobbies'>Hobby:</label> 
        <select id='personHobbies' class='form-control'
          name='personHobbies' [(ngModel)]='activePerson.hobbyList[i]'
          [compareWith]='customCompareHobby'>
          <option *ngFor='let h of hobbyListSelect;' [ngValue]='h'>{{h.name}}</option>
        </select>

</div>
...
customCompareHobby(o1: Hobby, o2: Hobby) {
    return o1.id == o2.id;
}
14
cole

現在、angular 2には簡単な解決策はありませんが、angular 4では、これはベータ6以降で既に対処されています- https:// github .com/angular/angular/pull/13349

4
Klinki

選択したものにしたい場所から渡されたオブジェクトを取得したら、hobbyListSelect配列で一致するアイテムを検索し、見つかったアイテムをactivePerson.hobbyList[i]に割り当てるだけです。

0

この方法でngModelバインディングを使用する直接的なアプローチはありません。ただし、イベントハンドラーを個別に登録したくないため、オブジェクトの割り当て方法を変更する必要がある場合があります。また、目的を果たしていないため、selectタグにidを割り当てる必要はありません。上記のユースケースでは、双方向バインディングを表示するように変更しました。

モデルを使用してコンポーネントのコンストラクターを検索し、変更をテストするためだけにprintVal()が含まれます。テンプレートにはngValueとngModelが含まれていませんが、期待どおりに機能します。

constructor() {
    this.activePerson = {id: 'a1',
        hobbyList : [
           {
             id: 'h4'
           },
           {
             id : 'h2'
           }
          ]
      }
      
    this.hobbyListSelect = [
        {
         id: 'h1'
        },
        {
         id : 'h2'
        },
        {
         id: 'h3'
        },
        {
         id : 'h4'
        }
      ];
  }

printVal($event,i) {
    console.log(JSON.stringify(this.activePerson.hobbyList))
}
<div *ngFor='let a of activePerson.hobbyList ; let i=index; trackBy:a?.id'>
        <label for='personHobbies'>Hobby:</label>
        <select name='personHobbies' 
        (change)=" activePerson.hobbyList[i] = hobbyListSelect[$event.target.selectedIndex];
        printVal($event,i)">
            <option *ngFor='let h of hobbyListSelect; trackBy:h?.id' 
                [selected]='(h.id == a.id) ? "selected" : null'
            >
            {{h.id}}
            </option>
        </select>
    </div>
0
Ashwin Kumar