web-dev-qa-db-fra.com

Matériau angulaire: sélection du tapis sans sélection du paramètre par défaut

J'ai un tapis de sélection où les options sont tous les objets définis dans un tableau. J'essaie de définir la valeur par défaut sur l'une des options, mais cette option est laissée sélectionnée lors du rendu de la page.

Mon fichier TypeScript contient:

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

Mon fichier HTML contient:

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

J'ai essayé de définir selected2 et la value dans mat-option à la fois pour l'objet et son identifiant, et j'ai essayé d'utiliser à la fois [(value)] et [(ngModel)] dans mat-select, mais aucun ne fonctionne.

J'utilise la version matérielle 2.0.0-beta.10

Merci

51
William Moore

Utilisez une liaison pour la valeur dans votre modèle.

value="{{ option.id }}"

devrait être 

[value]="option.id"

Et dans la valeur que vous avez sélectionnée, utilisez ngModel au lieu de value.

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

devrait être 

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

Code complet:

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

Remarque: à partir de version 2.0.0-beta.12 le sélection de matériel accepte maintenant un élément mat-form-field comme élément parent, de sorte qu'il soit cohérent avec les autres contrôles d'entrée de matériau. Remplacez l'élément div par l'élément mat-form-field après la mise à niveau.

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

Utilisez compareWith, une fonction pour comparer les valeurs d’option aux valeurs sélectionnées. voir ici: https://material.angular.io/components/select/api#MatSelect

Pour un objet de la structure suivante:

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

Définissez le balisage comme ceci: 

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

Et définissez la fonction de comparaison comme ceci: 

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

J'utilise des formes angulaires 5 et réactives avec mat-select et je ne peux obtenir aucune des solutions ci-dessus pour afficher la valeur initiale. 

J'ai dû ajouter [compareWith] pour traiter les différents types utilisés dans le composant mat-select. En interne, il semble que mat-select utilise un tableau pour contenir la valeur sélectionnée. Cela permettra probablement au même code de fonctionner avec plusieurs sélections si ce mode est activé.

Angular Select Control Doc

Voici ma solution:

Form Builder pour initialiser le contrôle de formulaire:

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

Puis implémentez la fonction compareWith sur votre composant:

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

Créez et exportez ensuite la fonction DetermineI (je devais créer une fonction autonome pour que mat-select puisse l’utiliser): 

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

Enfin, ajoutez l’attribut compareWith à votre sélection de tapis:

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

Vous devriez le lier en tant que [value] dans le mat-option comme ci-dessous,

<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

10
Aravind

Ma solution est peu compliquée et plus simple. 

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

Je viens d'utiliser le espace réservé . La couleur par défaut de l'espace réservé au matériau est light gray. Pour donner l’impression que l’option est sélectionnée, je viens de manipuler le CSS comme suit:

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

Comme déjà mentionné dans Angular 6, utiliser ngModel sous des formes réactives est déconseillé (et supprimé dans Angular 7). J'ai donc modifié le modèle et le composant comme suit.

Le gabarit:

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

Les parties principales du composant (onChanges et d’autres détails sont omis):

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

Remarque this.filter.setValue (this.selected) in ngOnInit ci-dessus.

Cela semble fonctionner dans Angular 6.

3
mp31415

La solution pour moi était:

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


});

Utilisation de l'objet: {id: number, detalle: string}

1
Seba Arce

Essaye ça!

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

Je l'ai fait comme dans ces exemples. J'ai essayé de définir la valeur de la sélection de tapis sur la valeur de l'une des options de tapis. Mais a échoué. 

Mon erreur a été de faire [(value)] = "someNumberVariable" à une variable de type numérique alors que celles de mat-options étaient des chaînes. Même s'ils avaient le même aspect dans le modèle, cette option ne serait pas sélectionnée. 

Une fois, j’ai analysé le someNumberVariable en une chaîne, tout était parfait. 

Il semble donc que vous ayez besoin que les valeurs mat-select et mat-option soient non seulement le même nombre (si vous présentez des nombres), mais que vous les laissiez être de type string. 

1
jg80

Vous pouvez simplement implémenter votre propre fonction de comparaison

[compareWith]="compareItems"

Voir aussi le docu . Donc le code complet ressemblerait à ceci:

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

et dans le fichier TypeScript:

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