각도 재질 : 매트 선택 기본값을 선택하지 않음


109

옵션이 배열에 정의 된 모든 객체 인 매트 선택이 있습니다. 옵션 중 하나를 기본값으로 설정하려고하지만 페이지가 렌더링 될 때 선택된 상태로 남아 있습니다.

내 typescript 파일에는 다음이 포함됩니다.

  public options2 = [
    {"id": 1, "name": "a"},
    {"id": 2, "name": "b"}
  ]
  public selected2 = this.options2[1].id;

내 HTML 파일에는 다음이 포함됩니다.

  <div>
    <mat-select
        [(value)]="selected2">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

내가 설정을 시도 selected2하고을 valuemat-option목적과의 ID 모두, 모두 사용하여 시도 [(value)][(ngModel)]mat-select, 그러나 아무도가 작동하지 않습니다.

재료 버전 2.0.0-beta.10을 사용하고 있습니다.


2
사용 compareWith. 더 우아합니다.
Badis Merabet 2018

있어야합니다. compareWith여기에서 badis 답변을 참조하십시오. stackoverflow.com/questions/47333171/…
bresleveloper

답변:


144

템플릿의 값에 바인딩을 사용합니다.

value="{{ option.id }}"

해야한다

[value]="option.id"

그리고 선택한 값 ngModel에서 value.

<mat-select [(value)]="selected2">

해야한다

<mat-select [(ngModel)]="selected2">

완전한 코드 :

<div>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</div>

등의 측면에서 주 버전 2.0.0-beta.12 재료 선택 지금 받아들이 mat-form-field는 다른 재료 입력 컨트롤과 일치되도록 부모 요소로서 요소. 업그레이드 후 div요소를 mat-form-field요소로 대체하십시오 .

<mat-form-field>
  <mat-select [(ngModel)]="selected2">
    <mat-option *ngFor="let option of options2" [value]="option.id">{{ option.name }}</mat-option>
  </mat-select>
</mat-form-field>

10
"formControlName과 동일한 양식 필드에서 ngModel을 사용중인 것 같습니다. 반응 양식 지시문과 함께 ngModel 입력 속성 및 ngModelChange 이벤트 사용에 대한 지원은 Angular v6에서 더 이상 사용되지 않으며 Angular v7에서 제거됩니다. 자세한 내용은 , 여기에서 API 문서를 참조하십시오. angular.io/api/forms/FormControlName#use-with-ngmodel "
ldgorman

1
@ldgorman-나는 당신이 그 결론을 어떻게 이끌어 내는지 모르겠습니다. 을 언급하는 mat-form-field경우 이것은 ..."used to wrap several Angular Material components and apply common Text field styles"이므로 같은 것이 아닙니다. 영업 및도 내 대답은 언급도하지 않았보다 다른 FormControl, FormGroup또는 FormControlName.
Igor

1
위와 동일한 코드를 구현 한 후에도 동일한 문제가 발생합니다 @Igor
Chuck

@ 척-여전히 문제가있는 경우 새로운 질문을하고 재현 가능한 최소한의 예를 포함하십시오 . 내가 살펴보고 싶다면 해당 질문에 대한 링크와 함께이 댓글에 답장 할 수 있습니다.
Igor

2
@ Igor- 우리는 그것을 알아 냈고, 값은 숫자로 반환되고 Mat는 문자열을 찾고 선택했습니다. [compareWith]지시어는 우리가 사용하는 것입니다

94

사용 compareWith, 함수는 선택된 값으로 옵션 값을 비교합니다. 여기를 참조하십시오 : https://material.angular.io/components/select/api#MatSelect

다음 구조의 객체 :

listOfObjs = [{ name: 'john', id: '1'}, { name: 'jimmy', id: '2'},...]

다음과 같이 마크 업을 정의하십시오.

<mat-form-field>
  <mat-select
    [compareWith]="compareObjects"
    [(ngModel)]="obj">
       <mat-option  *ngFor="let obj of listOfObjs" [value]="obj">
          {{ obj.name }}
       </mat-option>
    </mat-select>
</mat-form-field>

그리고 다음과 같이 비교 함수를 정의하십시오.

compareObjects(o1: any, o2: any): boolean {
  return o1.name === o2.name && o1.id === o2.id;
}

8
단순한 배열이 아닌 객체를 다룰 때 완벽합니다. 감사합니다.
Riaan van Zyl

25

저는 Angular 5와 반응 형을 mat-select와 함께 사용하고 있으며 위의 솔루션 중 하나를 사용하여 초기 값을 표시 할 수 없습니다.

매트 선택 구성 요소 내에서 사용되는 다른 유형을 처리하기 위해 [compareWith]를 추가해야했습니다. 내부적으로 mat-select는 선택된 값을 보유하기 위해 배열을 사용합니다. 이 모드가 켜져있는 경우 동일한 코드가 여러 선택 항목과 함께 작동 할 수 있습니다.

각도 선택 제어 문서

내 해결책은 다음과 같습니다.

양식 컨트롤을 초기화하는 양식 작성기 :

this.formGroup = this.fb.group({
    country: new FormControl([ this.myRecord.country.id ] ),
    ...
});

그런 다음 구성 요소에서 compareWith 함수를 구현하십시오.

compareIds(id1: any, id2: any): boolean {
    const a1 = determineId(id1);
    const a2 = determineId(id2);
    return a1 === a2;
}

다음으로 determinId 함수를 만들고 내 보냅니다 (mat-select에서 사용할 수 있도록 독립형 함수를 만들어야 함).

export function determineId(id: any): string {
    if (id.constructor.name === 'array' && id.length > 0) {
       return '' + id[0];
    }
    return '' + id;
}

마지막으로 mat-select에 compareWith 속성을 추가하십시오.

<mat-form-field hintLabel="select one">
<mat-select placeholder="Country" formControlName="country" 
    [compareWith]="compareIds">

    <mat-option>None</mat-option>
    <mat-option *ngFor="let country of countries" [value]="country.id">
                        {{ country.name }}
    </mat-option>
</mat-select>
</mat-form-field>

감사합니다! 원인을 찾는 것은 매우 어려웠습니다.
Pax Beach

@ Heather92065 이것은 나를 위해 일한 유일한 솔루션입니다. 나는 당신에게 매우 감사합니다!
Latin Warrior

16

당신은 그것을 바인딩해야 [value]에서 mat-option아래와 같이

<mat-select placeholder="Panel color" [(value)]="selected2">
  <mat-option *ngFor="let option of options2" [value]="option.id">
    {{ option.name }}
  </mat-option>
</mat-select>

라이브 데모


이것은 완벽하게 작동합니다. ngModel setValue의 ()이 가장 쉽고 완벽한 방법으로 사용하는 Insted
Rohit 음부

10

자신 만의 비교 기능을 간단히 구현할 수 있습니다.

[compareWith]="compareItems"

문서 도 참조하십시오 . 따라서 전체 코드는 다음과 같습니다.

  <div>
    <mat-select
        [(value)]="selected2" [compareWith]="compareItems">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

그리고 Typescript 파일에서 :

  compareItems(i1, i2) {
    return i1 && i2 && i1.id===i2.id;
  }

이것은 나를 위해 일했으며 이것이 대부분 올바른 방법이라고 생각하지만 목록에 하나의 요소 만 포함되어 있으면 작동하지 않습니다. 감사합니다
코드 Kadiya

하나의 요소로 어떤 종류의 예외가 발생합니까? 비교가 존재 i1하거나 i2존재하지 않을 경우 담당해야하기 때문 입니다.
LeO

6

Angular 6에서 이미 언급했듯이 반응 형으로 ngModel을 사용하는 것은 더 이상 사용되지 않으며 Angular 7에서는 제거되었으므로 다음과 같이 템플릿과 구성 요소를 수정했습니다.

템플릿 :

<mat-form-field>
    <mat-select [formControl]="filter" multiple 
                [compareWith]="compareFn">
        <mat-option *ngFor="let v of values" [value]="v">{{v.label}}</mat-option>
    </mat-select>
</mat-form-field>

구성 요소의 주요 부분 ( onChanges및 기타 세부 사항은 생략 됨) :

interface SelectItem {
    label: string;
    value: any;
}

export class FilterComponent implements OnInit {
    filter = new FormControl();

    @Input
    selected: SelectItem[] = [];

    @Input()
    values: SelectItem[] = [];

    constructor() { }

    ngOnInit() {
        this.filter.setValue(this.selected);
    }

    compareFn(v1: SelectItem, v2: SelectItem): boolean {
        return compareFn(v1, v2);
    }
}

function compareFn(v1: SelectItem, v2: SelectItem): boolean {
    return v1 && v2 ? v1.value === v2.value : v1 === v2;
}

위의 this.filter.setValue (this.selected) 를 참고하십시오 ngOnInit.

Angular 6에서 작동하는 것 같습니다.


비교할 두 개의 서로 다른 API 결과를 처리 할 때 객체 선택도 다루기 때문에 이것은 실제로 가장 좋은 대답이어야합니다.
Marco Klein

(예 : 선택할 항목의 총 목록과 다른 API 호출 내에서 선택한 항목).
Marco Klein

Angular 7은 여전히 ​​템플릿 기반 모델에서 작동합니다! 그러나 동일한 템플릿에서 반응 형 양식과 혼합 할 수 없습니다. 와 힌트는 [compareWith]좋았어요
레오

3

이 예제에서와 같이했습니다. mat-select의 값을 mat-options 중 하나의 값으로 설정하려고했습니다. 그러나 실패했습니다.

내 실수는 숫자 형 변수에 [(value)] = "someNumberVariable"을 수행하는 반면 mat-options의 변수는 문자열이었습니다. 템플릿에서 동일하게 보이지만 해당 옵션을 선택하지 않습니다.

someNumberVariable을 문자열로 파싱하면 모든 것이 완전히 괜찮 았습니다.

따라서 mat-select 및 mat-option 값은 동일한 숫자 일뿐만 아니라 (숫자를 제시하는 경우) 문자열 유형이어야합니다.


그것도 제 문제였습니다. 하나는 숫자이고 다른 하나는 문자열이었습니다.
Vadim Berman 19

2

저에게 해결책은 다음과 같습니다.

<mat-form-field>
  <mat-select #monedaSelect  formControlName="monedaDebito" [attr.disabled]="isLoading" [placeholder]="monedaLabel | async ">
  <mat-option *ngFor="let moneda of monedasList" [value]="moneda.id">{{moneda.detalle}}</mat-option>
</mat-select>

TS :

@ViewChild('monedaSelect') public monedaSelect: MatSelect;
this.genericService.getOpciones().subscribe(res => {

  this.monedasList = res;
  this.monedaSelect._onChange(res[0].id);


});

개체 사용 : {id : number, detalle : string}


1

이 시도!

this.selectedObjectList = [{id:1}, {id:2}, {id:3}]
this.allObjectList = [{id:1}, {id:2}, {id:3}, {id:4}, {id:5}]
let newList = this.allObjectList.filter(e => this.selectedObjectList.find(a => e.id == a.id))
this.selectedObjectList = newList

1

내 솔루션은 조금 까다 롭고 간단합니다.

<div>
    <mat-select
        [placeholder]="selected2">
      <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>

방금 자리 표시자를 사용했습니다 . 재료 자리 표시 자의 기본 색상은입니다 light gray. 옵션이 선택된 것처럼 보이게하기 위해 다음과 같이 CSS를 조작했습니다.

::ng-deep .mat-select-placeholder {
    color: black;
}

1

바인딩 또는 기본 값으로 설정하면 경우에만 작동 에 대한 속성 MatSelect가 에 필적 에 바인더 제본 속성 MatOption . 바인딩하면caption 에 당신의 품목의 의 속성 매트 옵션 당신의 기본 요소로 설정해야합니다 요소 매트 - 선택caption너무 귀하의 항목. 당신이 결합하는 경우 Id에 당신의 품목의 매트 옵션 , 당신은 바인딩해야 id매트 선택 도 아닌 전체 항목, 자막 또는 기타 만 같은 분야를.

그러나 당신은 바인딩 []로해야합니다


1

위의 내용을 매우 신중하게 따랐지만 여전히 초기 값을 선택할 수 없었습니다.

그 이유는 바인딩 된 값이 typescript에서 문자열로 정의되었지만 내 백엔드 API가 숫자를 반환했기 때문입니다.

Javascript 느슨한 입력은 단순히 런타임에 유형을 변경하여 (오류없이) 초기 값을 선택할 수 없게했습니다.

구성 요소

myBoundValue: string;

주형

<mat-select [(ngModel)]="myBoundValue">

해결책은 문자열 값을 반환하도록 API를 업데이트하는 것입니다.


1

이를 달성하는 매우 간단한 방법 은 예를 들어 (선택 사항) formControl안에 기본값과 함께를 사용하는 것 입니다 FormGroup. 다음은 영역 입력에 단위 선택기를 사용하는 예입니다.

TS

H_AREA_UNIT = 1;
M_AREA_UNIT = 2;

exampleForm: FormGroup;

this.exampleForm = this.formBuilder.group({
  areaUnit: [this.H_AREA_UNIT],
});

HTML

<form [formGroup]="exampleForm">
 <mat-form-field>
   <mat-label>Unit</mat-label>
   <mat-select formControlName="areaUnit">
     <mat-option [value]="H_AREA_UNIT">h</mat-option>
     <mat-option [value]="M_AREA_UNIT">m</mat-option>
   </mat-select>
 </mat-form-field>
</form>

0

숫자와 문자열의 비교는 거짓으로 사용됩니다. 이므로 선택한 값을 ngOnInit 내의 문자열로 캐스팅하면 작동합니다.

나는 같은 문제가 있었고 mat-select를 열거 형으로 채웠습니다.

Object.keys(MyAwesomeEnum).filter(k => !isNaN(Number(k)));

선택하고 싶은 enum 값이 있습니다.

나는 그것이 작동하지 않는 이유를 확인하기 위해 내 마음을 힘들게하는 데 몇 시간을 보냈다. 매트 선택, 키 컬렉션 및 선택된 변수에 사용되는 모든 변수를 렌더링 한 직후에 수행했습니다. [ "0", "1", "2"]가 있고 1을 선택하려는 경우 ( 숫자 임) 1 == "1"은 거짓이며 아무것도 선택되지 않았기 때문입니다.

따라서 해결책선택한 값을 ngOnInit 내의 문자열캐스팅 하는 것이며 작동합니다.


1
: 안녕 후안 당신은 JS 다른 평등 연산자에 대한 세부로 전환이 게시물을보고 할 수 있습니다 stackoverflow.com/questions/359494/...
윌리엄 무어

안녕하세요 William, 훌륭한 게시물입니다. 몇 번이나 가봤습니다. 제대로 비교하는 방법을 배웠습니다. (항상 문서를 검토 할 수 있기를 바랍니다.) 여기에서 문제는 바인딩이 강제로 다른 유형, 숫자 및 문자열을 사용하는 소재 컨트롤러 ... 해당 컨트롤러는 동일한 유형을 가질 것으로 예상하므로 선택하면 숫자가 컬렉션이어야합니다. 그게 문제였습니다.
Juan

0

나는 이걸했다.

<div>
    <mat-select [(ngModel)]="selected">
        <mat-option *ngFor="let option of options" 
            [value]="option.id === selected.id ? selected : option">
            {{ option.name }}
        </mat-option>
    </mat-select>
</div>

[value]="option"일부 데이터베이스에서 옵션을 얻지 않는 한 일반적으로 할 수 있습니까 ?? 데이터를 가져 오는 것이 지연되어 작동하지 않거나 객체가 동일하더라도 어떤 식 으로든 다른 것 같습니다.? 이상하게도 나도 시도했지만 [value]="option === selected ? selected : option"작동하지 않았기 때문에 나중에 가장 가능성이 높습니다 .


0

TS

   optionsFG: FormGroup;
   this.optionsFG = this.fb.group({
       optionValue: [null, Validators.required]
   });

   this.optionsFG.get('optionValue').setValue(option[0]); //option is the arrayName

HTML

   <div class="text-right" [formGroup]="optionsFG">
     <mat-form-field>
         <mat-select placeholder="Category" formControlName="optionValue">
           <mat-option *ngFor="let option of options;let i =index" [value]="option">
            {{option.Value}}
          </mat-option>
        </mat-select>
      </mat-form-field>
  </div>

0

public options2 = [
  {"id": 1, "name": "a"},
  {"id": 2, "name": "b"}
]
 
YourFormGroup = FormGroup; 
mode: 'create' | 'update' = 'create';

constructor(@Inject(MAT_DIALOG_DATA) private defaults: defautValuesCpnt,
      private fb: FormBuilder,
      private cd: ChangeDetectorRef) {
}
  
ngOnInit() {

  if (this.defaults) {
    this.mode = 'update';
  } else {
    this.defaults = {} as Cpnt;
  }

  this.YourFormGroup.patchValue({
    ...
    fCtrlName: this.options2.find(x => x.name === this.defaults.name).id,
    ... 
  });

  this.YourFormGroup = this.fb.group({
    fCtrlName: [ , Validators.required]
  });

}
  <div>
    <mat-select formControlName="fCtrlName"> <mat-option
          *ngFor="let option of options2"
          value="{{ option.id }}">
        {{ option.name }}
      </mat-option>
    </mat-select>
  </div>


안전한 구성 요소에서 편집 및 업데이트를 사용할 때 도움이됩니다.
lilandos didas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.