Winkelmaterial: Mattenauswahl ohne Auswahl der Standardeinstellung


107

Ich habe eine Mattenauswahl, bei der die Optionen alle in einem Array definierten Objekte sind. Ich versuche, den Wert als Standard auf eine der Optionen zu setzen, er wird jedoch beim Rendern der Seite ausgewählt gelassen.

Meine Typoskriptdatei enthält:

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

Meine HTML-Datei enthält:

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

Ich habe versucht , Einstellung selected2und die valuein den mat-optionbeiden auf das Objekt und es ist id, und haben versucht , beide mit [(value)]und [(ngModel)]in der mat-select, aber keiner arbeiten.

Ich verwende Materialversion 2.0.0-beta.10


2
Verwenden Sie compareWith. Es ist eleganter.
Badis Merabet

MUSS HABEN compareWith, siehe Badis Antwort hier stackoverflow.com/questions/47333171/…
bresleveloper

Antworten:


144

Verwenden Sie eine Bindung für den Wert in Ihrer Vorlage.

value="{{ option.id }}"

sollte sein

[value]="option.id"

Und in Ihrem ausgewählten Wert ngModelanstelle von verwenden value.

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

sollte sein

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

Vollständiger Code:

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

Nebenbei bemerkt, ab Version 2.0.0-beta.12 akzeptiert die Materialauswahl jetzt ein mat-form-fieldElement als übergeordnetes Element, sodass es mit den anderen Materialeingabesteuerelementen übereinstimmt. Ersetzen Sie das Element nach dem Upgrade divdurch ein mat-form-fieldElement.

<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
"Es sieht so aus, als würden Sie ngModel im selben Formularfeld wie formControlName verwenden. Die Unterstützung für die Verwendung der Eingabeeigenschaft ngModel und des ngModelChange-Ereignisses mit reaktiven Formularanweisungen ist in Angular v6 veraltet und wird in Angular v7 entfernt. Weitere Informationen hierzu , siehe unsere API-Dokumente hier: angle.io/api/forms/FormControlName#use-with-ngmodel "
ldgorman

1
@ldgorman - Ich verstehe nicht, wie Sie diese Schlussfolgerung ziehen. Wenn Sie sich darauf beziehen, mat-form-fieldist dies ..."used to wrap several Angular Material components and apply common Text field styles"also nicht dasselbe. Anders als das die OP und auch meine Antwort nicht erwähnt FormControl, FormGroupoder FormControlName.
Igor

1
Ich habe das gleiche Problem, auch nachdem ich den gleichen Code wie oben implementiert habe @Igor
Chuck

@Chuck - Wenn Sie immer noch Probleme haben, stellen Sie bitte eine neue Frage und fügen Sie ein minimal reproduzierbares Beispiel bei . Wenn Sie möchten, dass ich einen Blick darauf werfen kann, können Sie auf diesen Kommentar mit einem Link zu dieser Frage antworten.
Igor

2
@ Igor- Wir haben es herausgefunden, der Wert wurde als Zahl zurückgegeben und die Mat-Auswahl hat nach einer Zeichenfolge gesucht. [compareWith]Direktive ist das, was wir benutzt haben
Chuck

92

Verwenden Sie die compareWithFunktion A, um die Optionswerte mit den ausgewählten Werten zu vergleichen. siehe hier: https://material.angular.io/components/select/api#MatSelect

Für ein Objekt mit folgender Struktur:

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

Definieren Sie Markup wie folgt:

<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>

Und definieren Sie die Vergleichsfunktion folgendermaßen:

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

8
Perfekt für Objekte und nicht für einfache Arrays. Danke dir.
Riaan van Zyl

25

Ich verwende Angular 5 und reaktive Formulare mit Mat-Select und konnte mit keiner der oben genannten Lösungen den Anfangswert anzeigen.

Ich musste [compareWith] hinzufügen, um mit den verschiedenen Typen umzugehen, die in der mat-select-Komponente verwendet werden. Intern scheint mat-select ein Array zu verwenden, um den ausgewählten Wert zu speichern. Dies ermöglicht wahrscheinlich, dass derselbe Code mit mehreren Auswahlen funktioniert, wenn dieser Modus aktiviert ist.

Angular Select Control Doc

Hier ist meine Lösung:

Form Builder zum Initialisieren des Formularsteuerelements:

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

Implementieren Sie dann die Funktion compareWith auf Ihrer Komponente:

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

Als nächstes erstellen und exportieren Sie die Funktion determinId (ich musste eine eigenständige Funktion erstellen, damit mat-select sie verwenden kann):

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

Fügen Sie abschließend das Attribut compareWith zu Ihrer Mattenauswahl hinzu:

<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>

Vielen Dank! Es war sehr schwierig, einen Grund zu finden.
Pax Beach

@ Heather92065 Dies ist die einzige Lösung, die für mich funktioniert hat. Ich bin dir sehr dankbar!
Latin Warrior

16

Sie sollten es wie [value]im mat-optionFolgenden binden ,

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

LIVE DEMO


Das funktioniert perfekt. Mit ngModel oder setValue () ist dies die einfachste und perfekteste Methode
Rohit Parte

10

Sie können einfach Ihre eigene Vergleichsfunktion implementieren

[compareWith]="compareItems"

Siehe auch das Dokument . Der vollständige Code würde also so aussehen:

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

und in der Typescript-Datei:

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

Dies funktioniert für mich und ich denke, dass dies meistens richtig ist, aber wenn die Liste nur ein Element enthält, funktioniert es nicht. Danke
Code Kadiya

Was für eine Ausnahme bekommen Sie mit nur einem Element? Denn der Vergleich sollte die Verantwortung übernehmen, wenn er nicht existiert i1oder i2nicht.
LeO

6

Wie bereits in Angular 6 erwähnt, ist die Verwendung von ngModel in reaktiven Formen veraltet (und in Angular 7 entfernt). Daher habe ich die Vorlage und die Komponente wie folgt geändert.

Die Vorlage:

<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>

Die Hauptteile der Komponente ( onChangesund andere Details werden weggelassen):

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;
}

Hinweis this.filter.setValue (this.selected) in ngOnInitoben.

Es scheint in Angular 6 zu funktionieren.


Dies sollte eigentlich die beste Antwort sein, da dies auch die Objektauswahl abdeckt, wenn zwei verschiedene API-Ergebnisse verglichen werden sollen.
Marco Klein

(zB Gesamtliste der Elemente, aus denen ausgewählt werden kann, und ausgewähltes Element innerhalb eines anderen API-Aufrufs).
Marco Klein

Angular 7 funktioniert immer noch mit Modellen mit Vorlagenantrieb! Sie können es jedoch nicht mit reaktiven Formen auf derselben Vorlage mischen. Ihr Hinweis mit dem [compareWith]war großartig
LeO

3

Ich habe es genauso gemacht wie in diesen Beispielen. Es wurde versucht, den Wert der Mattenauswahl auf den Wert einer der Mattenoptionen zu setzen. Aber scheiterte.

Mein Fehler war, [(value)] = "someNumberVariable" für eine numerische Typvariable auszuführen, während die in mat-options Zeichenfolgen waren. Selbst wenn sie in der Vorlage gleich aussehen würden, würde diese Option nicht ausgewählt.

Nachdem ich die someNumberVariable zu einer Zeichenfolge analysiert hatte, war alles in Ordnung.

Es scheint also, dass die Werte für mat-select und mat-option nicht nur dieselbe Zahl sein müssen (wenn Sie Zahlen präsentieren), sondern auch vom Typ string sein müssen.


Das war auch mein Problem. Einer war numerisch, der andere war eine Zeichenfolge.
Vadim Berman

2

Die Lösung für mich war:

<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);


});

Verwenden des Objekts: {id: number, detalle: string}


1

Versuche dies!

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

Meine Lösung ist etwas knifflig und einfacher.

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

Ich habe gerade den Platzhalter benutzt . Die Standardfarbe des Materialplatzhalters ist light gray. Damit es so aussieht, als wäre die Option ausgewählt, habe ich das CSS wie folgt bearbeitet:

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

1

Die Bindung oder der Standardwert Einstellung funktioniert nur , wenn der Wert Attribut auf MatSelect vergleichbar ist Wert Attribut binded MatOption . Wenn Sie binden captionIhre Artikel an Wert Attribut mat-Option Element Sie das Standardelement auf einstellen muß vlies wählen zu captionIhrem Artikel zu. Wenn Sie IdIhren Artikel an mat-option binden, müssen Sie auch idan mat-select binden , nicht an einen ganzen Artikel, eine Beschriftung oder ein anderes, sondern nur an dasselbe Feld.

Aber du musst es mit Bindung tun []


1

Ich habe die obigen Schritte sehr sorgfältig befolgt und konnte den Anfangswert immer noch nicht auswählen.

Der Grund war, dass meine Backend-API eine Zahl zurückgab, obwohl mein gebundener Wert im Typoskript als Zeichenfolge definiert war.

Durch die lose Eingabe von Javascript wurde der Typ einfach zur Laufzeit (ohne Fehler) geändert, wodurch die Auswahl des Anfangswertes verhindert wurde.

Komponente

myBoundValue: string;

Vorlage

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

Die Lösung bestand darin, die API zu aktualisieren, um einen Zeichenfolgenwert zurückzugeben.


1

Eine sehr einfache Möglichkeit, dies zu erreichen, ist die Verwendung von a formControlmit einem Standardwert, beispielsweise innerhalb von a FormGroup(optional). Dies ist ein Beispiel für die Verwendung eines Einheitenwählers für einen Bereichseingang:

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

Ein Vergleich zwischen einer Zahl und einer Zeichenfolge ist in der Regel falsch. Wenn Sie also den ausgewählten Wert in eine Zeichenfolge in ngOnInit umwandeln, funktioniert dies.

Ich hatte das gleiche Problem, ich füllte die Mattenauswahl mit einer Aufzählung mit

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

und ich hatte den Aufzählungswert, den ich auswählen wollte ...

Ich verbrachte einige Stunden damit, herauszufinden, warum es nicht funktionierte. Und ich habe es getan, nachdem ich alle Variablen gerendert hatte, die in der Mattenauswahl, der Schlüsselsammlung und der ausgewählten ... verwendet wurden, wenn Sie ["0", "1", "2"] haben und 1 auswählen möchten ( das ist eine Zahl) 1 == "1" ist falsch und deshalb wird nichts ausgewählt.

Die Lösung besteht also darin, den ausgewählten Wert in eine Zeichenfolge in ngOnInit umzuwandeln, und es funktioniert.


1
Hallo Juan, vielleicht möchten Sie sich diesen Beitrag ansehen, der die Details zu verschiedenen Gleichheitsoperatoren in JS beschreibt: stackoverflow.com/questions/359494/…
William Moore

Hallo William, das ist ein großartiger Beitrag, ich war schon einige Male dort ... Und ich habe gelernt, wie man richtig vergleicht (ich hoffe, und ich kann das Dokument immer überprüfen) ... Das Problem hier war, dass die Bindungen durch erzwungen wurden der Materialcontroller, bei dem verschiedene Typen, Nummern und Zeichenfolgen verwendet werden ... Dieser Controller erwartet dieselben Typen. Wenn also eine Nummer ausgewählt ist, muss die Sammlung eine Sammlung von Zahlen sein ... Das war das Problem.
Juan

0

Ich war das.

<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>

Normalerweise können Sie tun [value]="option", es sei denn, Sie erhalten Ihre Optionen aus einer Datenbank? Ich denke, entweder führt die Verzögerung beim Abrufen der Daten dazu, dass sie nicht funktionieren, oder die erhaltenen Objekte unterscheiden sich in gewisser Weise, obwohl sie gleich sind. Seltsamerweise ist es höchstwahrscheinlich das spätere, da ich es auch versucht habe [value]="option === selected ? selected : option"und es nicht funktioniert hat.


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>


Dies ist hilfreich, wenn Sie Edit & Update in der sicheren Komponente verwenden.
lilandos didas
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.