mat-select returns undefined on SelectionChange() - angular-material

I have mat-select on (selectionChange) event I'm receiving undefined as a value of $event.value. It returns correct value for first mat-option.mat-option with value 'All' it gives undefined
<mat-form-field>
<mat-select [(value)]="regionOption" (selectionChange)="regionSelectionChange($event)"
placeholder="Region">
<mat-option *ngFor="let region of regions" [value]="region.location_name">{{region.location_name}}</mat-option>
<mat-option [value]="All" >All</mat-option>
</mat-select>
</mat-form-field>
//ts
regionSelectionChange(regionName)
{
console.log(regionName);
}

Change your value binding from [value] to value
<mat-option value="All">All</mat-option>

I would go with this:
TS Code:
export class FormFieldOverviewExample {
regions: any[]= [{'location_name':"Pune"},{'location_name':"Mumbai"}];
constructor(){
this.regions.push({'location_name':"All"}); -- Will add a value in the constructor
}
regionSelectionChange(regionName) {
console.log(regionName.value);
}
}
HTML Code:
<mat-form-field>
<mat-select [(value)]="regionOption" (selectionChange)="regionSelectionChange($event)" placeholder="Region">
<mat-option *ngFor="let region of regions" [value]="region.location_name">{{region.location_name}}
</mat-option>
</mat-select>
</mat-form-field>
Working-Demo

Related

how to set id for every node in a angular material tree view, in order that every node is independent

I can I set node id for every node in a angular material tree view, in order that every node is independent.
the HTML code looks like this:
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
<button mat-icon-button disabled></button>
<mat-form-field appearance="legacy">
<input matInput type="text" [formControl]="locationField"/>
<mat-autocomplete #auto="matAutocomplete" >
<mat-option *ngFor="let filteredFieldResult of locationFieldResults" [value]="filteredFieldResult">
{{filteredFieldResult}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</mat-tree-node>
<mat-tree-node *matTreeNodeDef="let node; when: hasChild" matTreeNodePadding>
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.filename" matTreeNodeToggle>
<mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
{{node.item}}
</mat-tree-node>
</mat-tree>
<button (click)="addNode()">Add Node</button>
<button (click)="addSubNode()">Add SubNode</button>
<button (click)="changeNode()">Change Node</button>
You can include that id into the structure of the node you are creating.
example:
export class MyFlatNode{
constructor(public name: string, public level = 1, public expandable = false, public loadMoreParentItem: string | null = null, public id:number = 0, public parentId: number=0) {}
}
and while creating the node for the tree, I used the following code in the transformer method given by material angular.
newNode = new MyFlatNode(node.name, node.level, node.hasChildren, null, node.id, node.parentId);
As you can see above, that I have passed all the information like node name, node level and node id etc. you can pass any information that you would possibly need in your tree nodes.
You can also do the same for the nested tree node by using the appropriate class constructor.

how to get index of selected item in mat autocomplete?

Is there any events for mat-option which is used for mat-autocomplete.
HTML code below:
<mat-form-field>
<input type="text" placeholder="Search......." aria-label="Number" style="text-transform: uppercase"
matInput formControlName="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption (optionSelected)=getSelectedClient($event.option);>
<mat-option *ngFor="let option of displayList; let i = index" [value]="option">
{{option}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
I want to get the index of the selected item.
please help me!
You can use click event on Mat-Option
Replace your mat-option with:
<mat-option (click)="onSelect(option,i)" *ngFor="let option of displayList; let i = index" [value]="option">
{{option}}
</mat-option>
in TS file:
onSelect(value,index) {
console.log('value --> ',value) // Value
console.log('index --> ',index) // Index that you need
}
A Working StackBlitz Example
Demo with option's index selected
You have to map the value of the index variable, let i = index to the value of the option in the autocomplete component.
<mat-autocomplete #auto="matAutocomplete"
autoActiveFirstOption
(optionSelected)="selectedOption($event)">
<mat-option *ngFor="let option of displayList; let i = index" [value]="i">
{{option}}
</mat-option>
</mat-autocomplete>
In component file:
selectedOption(event) {
const selectedValue = event.option.value;
console.log(selectedValue);
}
Demo Application Code: https://stackblitz.com/edit/angular-material-autocomplete-index-select?file=app/autocomplete-overview-example.html
Please comment, if this is not the required case.

Connecting dynamically generated input field to mat-autocomplete

I am allowing users to create input fields dynamically. For each of these input fields i want to connect it to a different mat-autocomplete so that they work independently of each other. I have hit a brick wall here because I cannot create element reference(#auto here) dynamically that connects the auto-complete to input. How do I achieve this?
<div
class="row"
*ngFor="let field of getControls('requestFields'); let i = index"
formArrayName="requestFields"
>
<ng-container [formGroupName]="i">
<div class="col-md-4">
<mat-form-field class="example-full-width">
<input
type="text"
placeholder="Name"
matInput
formControlName="reqName"
matAutocomplete="auto"
/>
<mat-autocomplete #auto="matAutocomplete">
<mat-option
*ngFor="let option of (filteredColumns | async)"
[value]="option"
>
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<div class="col-md-2">
<div class="togglebutton">
<label>
<span>Optional</span>
<input type="checkbox" formControlName="reqOption" />
<span class="toggle"></span>
</label>
</div>
</div>
<div class="col-md-4">
<mat-form-field>
<input
matInput
formControlName="reqValidations"
placeholder="Validation"
type="text"
/>
</mat-form-field>
</div>
</ng-container>
</div>
A nice thing about mat-autocomplete is that it is completely decoupled from the mat-form-field therefore you can put it at any place outside the scope of dynamically-generated rows. So taking your example - the solution could look like this:
<div
class="row"
*ngFor="let field of getControls('requestFields'); let i = index"
formArrayName="requestFields"
>
<ng-container [formGroupName]="i">
<div class="col-md-4">
<mat-form-field class="example-full-width">
<input
type="text"
placeholder="Name"
matInput
formControlName="reqName"
matAutocomplete="auto"
/>
</mat-form-field>
</div>
<!-- other dynamic content -->
</ng-container>
</div>
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredColumns | async" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
Then you could have an event handler for keyup on the input that triggers update for filteredColumns
<mat-form-field class="example-full-width">
<input
type="text"
placeholder="Name"
matInput
formControlName="reqName"
matAutocomplete="auto"
(keyup)="reqNameChanged(field.get('reqName')?.value)"
/>
</mat-form-field>
And in your component you can set up an filteredColumns observable that gets triggered by a subject from the keyup event handler:
import { Component, OnInit } from '#angular/core';
import { Observable, Subject } from 'rxjs';
import {
debounceTime,
distinctUntilChanged,
filter,
switchMap
} from 'rxjs/operators';
#Component({
selector: 'example',
templateUrl: './example.html',
styleUrls: ['./example.scss']
})
export class ExampleComponent implements OnInit {
filteredColumns: Observable<string[]>;
reqNameSubject: Subject<string> = new Subject<string>();
constructor(private lookup: ILookupService) {}
ngOnInit() {
this.filteredColumns = this.reqNameSubject.pipe(
filter(v => !!v),
debounceTime(300),
distinctUntilChanged(),
switchMap(value =>
/* call for the autocomplete data */
this.lookup.search(value)
)
);
}
reqNameChanged(value: string) {
this.reqNameSubject.next(value);
}
}
I hope that it helps.

matTextareaAutosize overriding minimum row for Textarea

I have a textarea that I am trying to use matTextareaAutosize dynamically. I am using the buttons to change the showText value between true and false. However, it seems to be overriding the default rows being set with minRows. Now the default rows for the textarea is always 1. Is there a way assign default rows in a textarea with matTextareaAutosize being used?
Any help/suggestions would be much appreciated
textarea component.html
<mat-form-field>
<textarea matInput
class="descriptionText"
minRows="3"
[matTextareaAutosize]="showText"
#description
placeholder="{{ 'COLUMNS.description' | translate }}"
formControlName="description"
required>
</textarea>
<mat-error *ngIf="caseForm.invalid">{{ 'CASES.descriptionError' | translate }}</mat-error>
<mat-hint align="end">{{description.value.length}} / 1000</mat-hint>
</mat-form-field>
<div *ngIf="statusReason">
<button mat-button (click)="resizeDescription(true)">Show More</button>
<button mat-button (click)="resizeDescription(false)">Show Less</button>
</div>
component.ts
resizeDescription(value: boolean) {
this.showText = value;
}

Angular mat-autocomplete with dynamic inputs

I'm new in angular material design and I have a problem with mat-autocomplete for dynamic inputs. By default user see one input but when some value is selected than another input can be added and this is the tricky part - how to make that all those inputs will be using only one mat-autocomplete? Is it possible?
Below is code where I'm using mat-autocomplete. The addItem() function is adding another input which would be bind to the same mat-autocomplete. Should it be moved above ? And what about unique id? How can I solve this issue with multiple inputs connected to the same mat-autocomplete?
<div formArrayName="items" class="form-group"
*ngFor="let item of items.controls; let i = index">
<mat-form-field class="example-full-width">
<input required type="text" placeholder="Item ID"
matInput
[formControlName]="i"
[id]="i"
[matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async"
[value]="option.code"
(click)="selectOption(option, i)">
{{option.code}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<i *ngIf="i == 0 && selected" class="fa fa-plus add-vessel"
aria-hidden="true"
(click)="addItem()"></i>
<i *ngIf="i !== 0 && canRemove" class="fa fa-minus add-vessel"
aria-hidden="true"
(click)="removeItem(i)"></i>
</div>
You have to use multiple auto complete elements and all the inputs need to bind with array of valueChanges event capturing functions. The reason is if you're trying to bind valueChanges with formArray ("items") then the function will execute number of time that how many inputs in the array. Use the following code to achieve target.
for(var i = 0;i<numberOfInputElements;i++){
const items = this.form.get('items') as FormArray;
this.filteredOptions[index] = items.at(index).get('item').valueChanges
.pipe(
startWith(''),
map((value: string) => (value) ? this._filter(value, this.options) : this.options.slice())
);
}

Resources