alim1990
alim1990

Reputation: 4972

Angular 7 and angular material how to get the selected option text of mat-select instead of its value

I need to get the selected text of material drop down list <mat-select> instead of its value:

<ng-container matColumnDef="fr">
        <th mat-header-cell *matHeaderCellDef> Family Rel. </th>
        <td mat-cell *matCellDef="let element; let i = index;">
          <div [formGroupName]="i">
            <mat-form-field color="warn" appearance="outline">
              <mat-label>Family Relation</mat-label>
              <mat-select #familyRelation (selectionChange)="onChange(element, i, 'hh')" id="family_relation"
                formControlName="fr" placeholder="Family Relation">
                <mat-option *ngFor="let familyRelation of familyRelationArray;" [value]="familyRelation.family_relation_id">
                  {{familyRelation.family_relation_type}}
                </mat-option>
              </mat-select>
            </mat-form-field>&nbsp;
          </div>
        </td>
      </ng-container>

And here is how I am trying to do:

@ViewChild('familyRelation') familyRel: ElementRef;

And on change selection of the drop list:

onChange(data, i, type) {
    let c = this.familyRel.nativeElement.innerText;
    console.log(c)
}

I had the following error:

ERROR TypeError: Cannot read property 'innerText' of undefined at

And when I remove innerText, the consoled value is:

undefined

What I need as you can see in the stackblitz, if I chosed Parent, I want to get Parent into a variable and not 1 which is its id.

Please note that element, i and hh in (selectionChange)=onChange(element,...) are used later in the function, so forget about it now.

Upvotes: 10

Views: 28912

Answers (6)

Bharath Chowdary
Bharath Chowdary

Reputation: 1

You can use this method.

<mat-select [(ngModel)]="job" #jobMatSelect placeholder="-Select Job-" class="form-control" required>
 <mat-option *ngFor="let item of Jobs" [value]="item.jobId" [disabled]="item.status == false" [ngClass]="{'col-red':item.status == false}"> ({{item.viewValue}})</mat-option>
 </mat-select>

Component.ts

 @ViewChild('jobMatSelect') private jobMatSelected: MatSelect;
 this.jobSelected = this.jobMatSelected.triggerValue;

Upvotes: 0

Pork Jackson
Pork Jackson

Reputation: 399

Although it is a bit late, but answers have inspired me a bit, here is an idea:

export interface IFamilyGroup{
    id: number;
    name: string;
    address: string;
}

familyGroup: IFamilyGroup[];

getSelectOption( family: IFamilyGroup ): void {
    console.log(family);
}

<mat-select (selectionChange)="getSelectOption( familyGroup[$event.value] )">
  <mat-option>none</mat-option>
  <mat-option
    *ngFor="let family of familyGroup; let i = index"
    value="{{i}}">
        {{ family.name }}
    </mat-option>
</mat-select>

The disadvantage of this method is that you cannot use formControlName, because mat-option uses index as value, so if you want to match formgroup, you can change it to this:

// this is formgroup data model
export interface IFamilyGroup{
    id: number;
    name: string;
    address: string;
}

export interface IFormGroupDataForm{
    family: FormControl;
    whatever1?: FormControl;
    whatever2?: FormControl;
}


dataForm: FormGroup;
family = new FormControl();

familyGroup: IFamilyGroup[];

constructor(
    private formBuilder: FormBuilder
  ) { }

ngOnInit(): void {
    this.initFormGroup();
}

private initFormGroup() {
    dataForm = this.fromFormGroupModel({
      family: this.family
      // any you need...
    });
}

private fromFormGroupModel( model: IFormGroupDataForm ): FormGroup {
    return this.formBuilder.group(model);
}


getSelectOption( family: IFamilyGroup ): void {
    this.family.setValue(family); // set family data object be value
}



<div [formGroup]="dataForm">
    <mat-select (selectionChange)="getSelectOption( familyGroup[$event.value] )">
      <mat-option>none</mat-option>
      <mat-option
        *ngFor="let family of familyGroup; let i = index"
        value="{{i}}">
            {{ family.name }}
        </mat-option>
    </mat-select>

    //...
</div>

Upvotes: 1

Vi100
Vi100

Reputation: 4203

Sorry for being late to the party. I'm really horrified of reading all answers above...

The solution is much easier and direct than any of the proposed answers, as the select component just passes the selected model as part of the selectionChange argument.

But first, some corrections to your example. You've declared an interface, so USE IT:

export interface FamilyRelation {
    id: number;
    type: string;
}

So, in your constructor:

 constructor() {
    this.familyRelationArray=[
    {
      id: 1,
      type: 'Parent'
    },
    {
      id: 2,
      type: 'Sister'
    }
  ]
}

and not what you put in your StackBlitz... Then your view will become this:

<mat-select (selectionChange)="onChange($event)" id="family_relation" placeholder="Family Relation">
    <mat-option *ngFor="let familyRelation of familyRelationArray;" [value]="familyRelation.id">
        {{familyRelation.type}}
    </mat-option>
</mat-select>

No need for the (click) handler for every mat-option, since it isn't necessary and could lead to performance issues if you have a lot of options. Now, on the controller:

onChange(ev: any) {
   let optionText = ev.source.selected.viewValue;
   console.log(optionText);
}

or, if you prefer, the typed variant:

onChange(ev: MatSelectChange) {
   let optionText = (ev.source.selected as MatOption).viewValue;  //use .value if you want to get the key of Option
   console.log(optionText);
}

but don't forget the imports...

import { MatSelectChange } from '@angular/material/select';
import { MatOption } from '@angular/material/core';

Upvotes: 16

jakubm
jakubm

Reputation: 422

You can add index to loop with mat-option then pass it to onChange() method and it will allow you to get the selected element from array.

<mat-select #familyRelation (selectionChange)="onChange($event.value, element, i, 'hh')" id="family_relation" placeholder="Family Relation">
    <mat-option *ngFor="let familyRelation of familyRelationArray; let i=index" [value]="i">
        {{familyRelation.family_relation_type}}
    </mat-option>
</mat-select>

 

 onChange(index, data, i, type) {
    console.log(this.familyRelationArray[index].family_relation_type);
}

Here you have update code: link

Upvotes: 4

Rohit.007
Rohit.007

Reputation: 3502

Updated the code, and added click event on the options

https://stackblitz.com/edit/angular-material-w89kwc?embed=1&file=app/app.component.ts

Added one function

  getInnerText(innerText){
    console.log(innerText)
  }

Added click event in view

<mat-option *ngFor="let familyRelation of familyRelationArray;" [value]="familyRelation.family_relation_id" (click)="getInnerText(familyRelation.family_relation_type)">
    {{familyRelation.family_relation_type}}
</mat-option>

Upvotes: 3

Sachila Ranawaka
Sachila Ranawaka

Reputation: 41397

Use the compareWith

 <mat-select #familyRelation [compareWith]="compareFn" id="family_relation"  formControlName="fr" placeholder="Family Relation">
      <mat-option *ngFor="let familyRelation of familyRelationArray;" [value]="familyRelation.family_relation_id">
          {{familyRelation.family_relation_type}}
     </mat-option>
 </mat-select>


compareFn(data1 , data2){

}

compareWith listen to the 'change' event because 'input' events aren't fired for selects in Firefox. DOC.

Upvotes: 2

Related Questions