angular2 ngModel / ngValue选择选项对象 - 跨不同实例的相等性

时间:2016-10-30 02:16:08

标签: javascript angular equality angular2-forms

在发布之前,Angular2的各个版本已多次询问此问题的风味。但是,我还没有找到任何可以产生所需行为的东西(我想避免的解决方法):Select Object Problems

我的表单选择通过[(ngModel)]与对象进行双向绑定,然后选择'选项'通过* ngFor生成类似对象的列表(全部由id区分)。在我的研究中,已多次提到Angular2使用JavaScript对象等效(通过实例),因此绑定模型中没有相同实例的对象将与列表不匹配。因此,它不会被显示为"选择"项目 - 打破" 2-way"数据绑定。

但是,我想为这些实例定义匹配的方法。已经尝试了一些似乎在互联网上浮现的解决方案,但我要么丢失了一小块,要么实施不正确。

我想避免的选项:

  • 绑定到ngModel中对象以外的内容(即id)。 ngValue是我想要利用的一个很好的帮助
  • 通过更改处理程序进行变通办法
  • 强制实例匹配(我从数据服务获取对象,并且不想重新定义它们以匹配......这似乎不必要地浪费资源)

理想情况下(这似乎已经在几个有解决方案的地方进行了讨论 - 在我的情况下解决方案不足),有可能为ngModel定义一个相等的标准来代替对象实例相等。

即。下面的最新尝试,其中h.id == a.id定义了属性" selected"。我不明白为什么这个"选择"属性不会被渲染 - 是否被ngModel以某种方式阻止?设置选中=' true' HTML中的手动似乎已修复,但使用[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如何处理,以及可能有哪些其他选项用于处理)。

非常感谢任何帮助。目标是获得&#34;变更&#34;按钮来更改基础模型并相应地更新选择框 - 我已将我的尝试集中在&#34; hobbyList。&#34;我试过Firefox和Chrome。谢谢!

5 个答案:

答案 0 :(得分:12)

Per @Klinki

  

目前在角度2中没有简单的解决方案,但在角度4中   自从beta 6使用以来,这已经得到了解决   compareWith    - 见https://github.com/angular/angular/pull/13349

说明拟议案例(see 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;
}

答案 1 :(得分:4)

目前在角度2中没有简单的解决方案,但在角度4中,这已经从beta 6开始解决了 - 请参阅https://github.com/angular/angular/pull/13349

答案 2 :(得分:0)

如果从某个地方传递了想要制作所选对象的对象,只需在hobbyListSelect数组中搜索匹配项,并将找到的项目分配给activePerson.hobbyList[i]

答案 3 :(得分:0)

以这种方式使用ngModel绑定没有直接的方法。 但是,由于您不希望单独注册事件处理程序,我们可能需要更改对象的分配方式。 此外,您无需为select标记分配id,因为它不符合目的。 对于上面提到的用例,我修改了它以查看双向绑定。

使用model查找组件的构造函数,并包含printVal()以测试更改。模板不包括ngValue和ngModel,它仍然可以按预期工作。

&#13;
&#13;
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))
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 4 :(得分:0)

[compareWith]解决了这个问题。只需在compareObj方法中更改要比较的对象的正确属性即可。

<select [compareWith]="compareObj"  [(ngModel)]="selectedObjects">
   <option *ngFor="let object of objects" [ngValue]="object">
      {{object.name}}
   </option>
</select>

compareObj(o1: Object, o2: Object) {
   return o1.id === o2.id;
}