เลือกองค์ประกอบที่จะผูกวัตถุในเชิงมุม


409

ฉันต้องการผูกองค์ประกอบที่เลือกลงในรายการของวัตถุ - ซึ่งง่ายพอ:

@Component({
   selector: 'myApp',
   template: `<h1>My Application</h1>
              <select [(ngModel)]="selectedValue">
                 <option *ngFor="#c of countries" value="c.id">{{c.name}}</option>
              </select>`
})
export class AppComponent{
    countries = [
       {id: 1, name: "United States"},
       {id: 2, name: "Australia"}
       {id: 3, name: "Canada"},
       {id: 4, name: "Brazil"},
       {id: 5, name: "England"}
     ];
    selectedValue = null;
}

ในกรณีนี้ดูเหมือนว่าselectedValueจะเป็นตัวเลข - รหัสของรายการที่เลือก

อย่างไรก็ตามจริง ๆ แล้วฉันต้องการผูกกับวัตถุในประเทศเพื่อให้selectedValueเป็นวัตถุแทนที่จะเป็นเพียง ID ฉันพยายามเปลี่ยนค่าของตัวเลือกดังนี้:

<option *ngFor="#c of countries" value="c">{{c.name}}</option>

แต่ดูเหมือนว่าจะไม่ทำงาน ดูเหมือนว่าจะวางวัตถุในของฉันselectedValue- แต่ไม่ใช่วัตถุที่ฉันคาดหวัง คุณสามารถเห็นนี้ในตัวอย่าง Plunker ของฉัน

ฉันพยายามเชื่อมโยงกับเหตุการณ์การเปลี่ยนแปลงเพื่อให้ฉันสามารถตั้งค่าวัตถุด้วยตนเองตามรหัสที่เลือก อย่างไรก็ตามปรากฏว่าเหตุการณ์การเปลี่ยนแปลงเกิดขึ้นก่อนที่จะมีการอัปเดต ngModel ที่ถูกผูกไว้ - หมายความว่าฉันไม่สามารถเข้าถึงค่าที่เลือกใหม่ ณ จุดนั้น

มีวิธีที่สะอาดในการผูกองค์ประกอบที่เลือกเข้ากับวัตถุด้วย Angular 2 หรือไม่?


เพิ่งรู้ว่า Plunk ของฉันทำงานแตกต่างกันเล็กน้อยใน IE กับ Chrome ไม่มีใครทำงานในแบบที่ฉันต้องการ แต่ FYI
RHarris

คำตอบ:


734
<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
  <option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>

ตัวอย่าง StackBlitz

หมายเหตุ: คุณสามารถใช้[ngValue]="c"แทน[ngValue]="c.id"ตำแหน่งที่ c เป็นวัตถุของประเทศที่สมบูรณ์

[value]="..."รองรับเฉพาะค่าสตริง
[ngValue]="..."รองรับประเภทใดก็ได้

ปรับปรุง

ถ้าvalueเป็นวัตถุอินสแตนซ์ที่เลือกไว้จะต้องเหมือนกันกับหนึ่งในค่า

ดูเพิ่มเติมการเปรียบเทียบแบบกำหนดเองที่เพิ่งเพิ่มเมื่อเร็ว ๆ นี้https://github.com/angular/angular/issues/13268 มีให้ตั้งแต่ 4.0.0-beta.7

<select [compareWith]="compareFn" ...

ดูแลถ้าคุณต้องการเข้าถึงภายในthiscompareFn

compareFn = this._compareFn.bind(this);

// or 
// compareFn = (a, b) => this._compareFn(a, b);

_compareFn(a, b) {
   // Handle compare logic (eg check if unique ids are the same)
   return a.id === b.id;
}

21
พยายาม แต่สิ่งนี้ดูเหมือนว่าจะผูกข้อมูลจากดรอปดาวน์เป็นรุ่นเท่านั้น หากเข้าสู่หน้าเว็บด้วยรุ่นที่ตั้งค่าแบบเลื่อนลงจะไม่ได้รับการตั้งค่าตามที่เหมาะสม ...
Strinder

13
@Strinder ข้อผิดพลาดบ่อยครั้งคือการใช้อินสแตนซ์วัตถุอื่นมานานselectedValueกว่าcของ (รายการเริ่มต้น) วัตถุที่แตกต่างกันถึงแม้จะมีคุณสมบัติและค่าเดียวกันไม่ทำงานมันก็จะต้องเป็นอินสแตนซ์ของวัตถุเดียวกัน
GünterZöchbauer

1
@ GünterZöchbauerใช่ คิดถึงความคิดแล้ว ดังนั้นจึงไม่มีวิธีที่ง่ายในการซิงค์โดยตรงกับรุ่นและรายการค่าหรือไม่ = ตลอดเวลาผ่าน onChange หรือไม่
Strinder

1
ในไม่ช้าเราอาจสามารถเปรียบเทียบออบเจ็กต์ ngModel โดยคุณสมบัติของพวกเขาโดยใช้ฟังก์ชันตัวเปรียบเทียบแบบกำหนดเอง เพียงแค่ดูปัญหานี้: github.com/angular/angular/issues/13268
kub1x

1
มันง่ายเสมอเมื่อคุณรู้ ;-) แต่angular.io/api/forms/NgSelectOption#descriptionมีลิงค์angular.io/api/forms/SelectControlValueAccessorด้วย docs ที่ดี
GünterZöchbauer

41

สิ่งนี้สามารถช่วย:

    <select [(ngModel)]="selectedValue">
          <option *ngFor="#c of countries" [value]="c.id">{{c.name}}</option>
    </select>

5
ฉันใช้ [ค่า] แทน [ngValue] มันไม่เหมือนกัน สิ่งนี้ใช้ได้สำหรับฉัน
Carolina Faedo

2
ข้อผิดพลาดใน '#' ในเชิงมุม 4
sea-kg

2
ใช้letแทน#@ sea-kg
Ashraful Islam

1
คำตอบนี้ไม่ได้รับค่าที่เลือก
San Jaisy

20

คุณสามารถทำได้เช่นกันโดยไม่จำเป็นต้องใช้[(ngModel)]ใน<select>แท็กของคุณ

ประกาศตัวแปรในไฟล์ ts ของคุณ

toStr = JSON.stringify;

และในแม่แบบที่คุณทำสิ่งนี้

 <option *ngFor="let v of values;" [value]="toStr(v)">
      {{v}}
 </option>

แล้วใช้

let value=JSON.parse(event.target.value)

เพื่อแยกสตริงกลับเข้าไปในวัตถุ JavaScript ที่ถูกต้อง


1
สิ่งนี้สามารถทำได้จริง แต่บนวัตถุขนาดใหญ่จะกลายเป็นความเจ็บปวด นอกจากนี้ขีดความสามารถในการตรวจจับการเปลี่ยนแปลงที่ขีดเส้นใต้ของแองกูลาร์เป็นสิ่งที่ควรคำนึงถึง ข้อมูลเอาต์พุตเป็น json แยกวิเคราะห์ได้ง่ายโดยบ็อตเพิ่มประสิทธิภาพการลาก การใช้การตรวจจับการเปลี่ยนแปลงของแองกูลาร์ (ห่อหุ้ม) ตรรกะของข้อมูลและรับรองถึงข้อมูลที่คุณต้องการ @GünterZöchbauerคำตอบเป็นวิธีการทำในเชิงมุม :)
Lucaci Andrei

ช่วยฉันที่ฉันมีรายการเดียวและการเปลี่ยนแปลงค่าใดอย่างหนึ่งไม่ควรจะปรับปรุงต่อไปเพื่อที่จะช่วยให้การใช้นี้เป็นสับโดยไม่ต้องใช้ ngmodel ให้ขอบคุณ :)
เมลวิน

ใช้งานได้กับวัตถุ JavaScript ธรรมดา แต่หมายเหตุสำหรับอินสแตนซ์ของคลาสที่คุณจะสูญเสียวิธีการทั้งหมดในชั้นเรียน
KhalilRavanna

13

มันใช้งานได้สำหรับฉัน:

เทมเพลต HTML:

ฉันเพิ่มของฉัน(ngModelChange)="selectChange($event)"select

<div>
  <label for="myListOptions">My List Options</label>
  <select (ngModelChange)="selectChange($event)" [(ngModel)]=model.myListOptions.id >
    <option *ngFor="let oneOption of listOptions" [ngValue]="oneOption.id">{{oneOption.name}}</option>
  </select>
</div>

บน component.ts:

  listOptions = [
    { id: 0, name: "Perfect" },
    { id: 1, name: "Low" },
    { id: 2, name: "Minor" },
    { id: 3, name: "High" },
  ];

คุณต้องเพิ่มcomponent.tsฟังก์ชั่นนี้:

  selectChange( $event) {
    //In my case $event come with a id value
    this.model.myListOptions = this.listOptions[$event];
  }

หมายเหตุ: ฉันลองด้วย[select]="oneOption.id==model.myListOptions.id"และไม่ทำงาน

============= วิธีอื่นได้: =========

เทมเพลต HTML:

ฉันเพิ่มของฉัน[compareWith]="compareByOptionIdselect

<div>
  <label for="myListOptions">My List Options</label>
  <select [(ngModel)]=model.myListOptions [compareWith]="compareByOptionId">
    <option *ngFor="let oneOption of listOptions" [ngValue]="oneOption">{{oneOption.name}}</option>
  </select>
</div>

บน component.ts:

  listOptions = [
    { id: 0, name: "Perfect" },
    { id: 1, name: "Low" },
    { id: 2, name: "Minor" },
    { id: 3, name: "High" },
  ];

คุณต้องเพิ่มcomponent.tsฟังก์ชั่นนี้:

 /* Return true or false if it is the selected */
 compareByOptionId(idFist, idSecond) {
    return idFist && idSecond && idFist.id == idSecond.id;
 }

นี่เป็นสิ่งที่ดีถ้าคุณต้องการจัดการกับเหตุการณ์การเปลี่ยนแปลงเพื่อทำสิ่งพิเศษ (เช่นแจ้งการเรียกกลับการเปลี่ยนแปลง) แต่ในกรณีที่คุณจะต้องใส่จากนั้นตั้งค่ารูปแบบของคุณด้วยตนเองในการเรียกกลับการเปลี่ยนแปลงที่คุณกำหนดเองที่กำหนดไว้ใน[ngModel] (ngModelChange)
บดขยี้

9

ในกรณีที่มีใครบางคนกำลังมองหาที่จะทำแบบเดียวกันโดยใช้แบบฟอร์มปฏิกิริยา:

<form [formGroup]="form">
  <select formControlName="country">
    <option *ngFor="let country of countries" [ngValue]="country">{{country.name}}</option>
  </select>
  <p>Selected Country: {{country?.name}}</p>
</form>

ตรวจสอบตัวอย่างการทำงานที่นี่


5

คุณสามารถเลือกรหัสโดยใช้ฟังก์ชั่น

<option *ngFor="#c of countries" (change)="onchange(c.id)">{{c.name}}</option>

4

สำหรับฉันมันทำงานเช่นนี้คุณสามารถปลอบevent.target.valueใจ

<select (change) = "ChangeValue($event)" (ngModel)="opt">   
    <option *ngFor=" let opt of titleArr" [value]="opt"></option>
</select>

2

นอกจากนี้หากไม่มีสิ่งใดจากโซลูชันที่ให้มาใช้งานไม่ได้ให้ตรวจสอบว่าคุณนำเข้า "FormsModule" ด้านในของ "AppModule" นั่นเป็นกุญแจสำคัญสำหรับฉันหรือไม่


2

สร้างทะเยอทะยานอื่นสำหรับรายการที่เลือก

<form [formGroup]="countryForm">
  <select formControlName="country">
    <option *ngFor="let c of countries" [value]="c.id">{{c.name}}</option>
  </select>

  <p>Selected Country: {{selectedCountry?.name}}</p>
</form>

ใน ts:

get selectedCountry(){
  let countryId = this.countryForm.controls.country.value;
  let selected = this.countries.find(c=> c.id == countryId);
  return selected;
}

1

คุณสามารถรับค่าที่เลือกได้ด้วยความช่วยเหลือของการคลิก () โดยการส่งผ่านค่าที่เลือกผ่านฟังก์ชั่น

<md-select placeholder="Select Categorie"  
    name="Select Categorie" >
  <md-option *ngFor="let list of categ" [value]="list.value" (click)="sub_cat(list.category_id)" >
    {{ list.category }}
  </md-option>
</md-select>

0

ใช้วิธีนี้เช่นกัน ..

<h1>My Application</h1>
<select [(ngModel)]="selectedValue">
     <option *ngFor="let c of countries" value="{{c.id}}">{{c.name}}</option>
 </select>

0

ในapp.component.html:

 <select type="number" [(ngModel)]="selectedLevel">
          <option *ngFor="let level of levels" [ngValue]="level">{{level.name}}</option>
        </select>

และapp.component.ts:

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  levelNum:number;
  levels:Array<Object> = [
      {num: 0, name: "AA"},
      {num: 1, name: "BB"}
  ];

  toNumber(){
    this.levelNum = +this.levelNum;
    console.log(this.levelNum);
  }

  selectedLevel = this.levels[0];

  selectedLevelCustomCompare = {num: 1, name: "BB"}

  compareFn(a, b) {
    console.log(a, b, a && b && a.num == b.num);
    return a && b && a.num == b.num;
  }
}

0

<select name="typeFather"
    [(ngModel)]="type.typeFather">
        <option *ngFor="let type of types" [ngValue]="type">{{type.title}}</option>
</select>

วิธีการนั้นจะใช้งานได้เสมออย่างไรก็ตามหากคุณมีรายการแบบไดนามิกตรวจสอบให้แน่ใจว่าคุณโหลดก่อนรุ่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.