I have a dropdown code and i have used angular material 6.4.1.
<mat-form-field floatLabel="never">
<mat-select name="country" [formControl]="userForm['country']"
(selectionChange)="onCountryChange($event)">
<mat-option [value]="null">
None
</mat-option>
<mat-option *ngFor="let country of countries" [value]="country.id">
{{country.name}}
</mat-option>
</mat-select>
</mat-form-field>
If i select any country from the dropdown list onCountryChange() will trigger once, but if i change country value to None onCountryChange() is triggering 2 times.
Can any one help with this, i have tried different ways to resolve it but no luck.
Related
I want to call a function, once the value of dropdown is changed.
I have done this without Angular Material.
Here's my ts and html files.
selected="pending";
getRequests(event: any) {
this.selected = event.target.value;
if(this.selected=="pending")
console.log("Inside Pending Requests")
else
console.log("Inside Granted Requests")
}
<div style="margin-left: 70%;" appearance="fill">
<select (change)="getRequests($event)">
<option value="pending">Pending</option>
<option value="granted">Granted</option>
</select>
</div>
Now, I want to implement this with the help of Angular Material Select Component.
Calling the getRequests() function is not working as expected. Somebody please help me on this one. Thanks in advance.
<mat-form-field style="margin-left: 70%;" appearance="fill">
<mat-label>Status</mat-label>
<mat-select [(value)]="selected" (change)="getRequests($event)" >
<mat-option value="pending">Pending</mat-option>
<mat-option value="granted">Granted</mat-option>
</mat-select>
The api is selectionChange i.e. (selectionChange)="getRequests($event)".
See the docs https://material.angular.io/components/select/api
In Angular Material Design 6 and above, the (change) method was removed. Instead use selectionChange
<mat-select (selectionChange)="doSomething($event)">
Read more about here: Angular 6 Material mat-select change method removed
Use selectionChange intead of change
<mat-form-field style="margin-left: 70%;" appearance="fill">
<mat-label>Status</mat-label>
<mat-select [(value)]="selected" (selectionChange)="getRequests($event)" >
<mat-option value="pending">Pending</mat-option>
<mat-option value="granted">Granted</mat-option>
</mat-select>
Then you should be able to access value from event object value property
getRequests(event: MatSelectChange) {
this.selected = event.value;
if(this.selected=="pending")
console.log("Inside Pending Requests")
else
console.log("Inside Granted Requests")
}
Working Example
your mat-select has an event that is emitted every time selection is changed. It is called selectionChange as per angular documentation: https://material.angular.io/components/select/api
so maybe try to chage your (change) to (selectionChange) like this:
<mat-form-field style="margin-left: 70%;" appearance="fill">
<mat-label>Status</mat-label>
<mat-select [(value)]="selected" (selectionChange)="getRequests($event)" >
<mat-option value="pending">Pending</mat-option>
<mat-option value="granted">Granted</mat-option>
</mat-select>
I spent a lot of time solving this problem and failed. I want to select to display the name and get the id. The problem is, as soon as a value is selected, the number (id) of that value is displayed. My code:
<mat-form-field class="example-full-width">
<input
matInput
placeholder="Search your product"
formControlName="id"
[matAutocomplete] = "auto">
<mat-autocomplete #auto="matAutocomplete" >
<mat-option *ngFor="let option of allProducts; let i = index" [value]="option.id" >
{{ option.name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
I tried to create a function (onSelectionChange) but could not display the name and take the value as (id)
Well, you have to use the input function of auto-complete called displayWith.
you can find the solution to your problem in this link here
plus I 've made a stackblitz example for you to simplify it more.
Example
to describe the solution:
you have to add to your autocomplete component an input called displayWith
<mat-autocomplete #auto="matAutocomplete" [displayWith]="checkValue">
and then in your component you have to create the function checkValue
checkValue(value: any) {
// here you can get your id or whatever you want
console.log(value)
}
then you have to add to your mat option the value and give it your whole object as value
<mat-option *ngFor="let option of options" [value]="option" >
{{option.name}}
</mat-option>
Please check the stackblitz example for more details
<mat-form-field appearance="outline" fxFlex="25" class="pr-12" *ngFor="let htmlMarketLevel of marketLevels">
<mat-label>{{htmlMarketLevel.MarketLevelName}}</mat-label>
<mat-select name="Market{{htmlMarketLevel.Rank}}" [(ngModel)]="selectedMarket[htmlMarketLevel.Rank]" [compareWith]="compareMarkets" (selectionChange)="populateChildrenMarkets( $event )">
<mat-option>All</mat-option>
<mat-option *ngFor="let market of markets[htmlMarketLevel.Rank]" [value]="market">{{market.MarketName}}</mat-option>
</mat-select>
</mat-form-field>
I have multiple select fields that are generated dynamically. Now I have an issue, if my select field is populated and an option is selected it's not firing the selectionChange event. But if it's a user action then it's firing the event.
I need to set default value if there is one one option in the mat-select. otherwise leave black to select by user.
This is my code in HTML
<mat-form-field>
<mat-select (selectionChange)="CompartSelected($event, element, cmpart)" disableRipple [value]="element.Compart.Id" name="cmpart" >
<mat-option *ngIf="getAvailableCompartList(element.Compart.CompartType.Id).length > 1" value="">-- Please Select an Option --</mat-option>
<mat-option *ngFor="let cmpart of getAvailableCompartList(element.Compart.CompartType.Id)" title="{{Translate(cmpart.CompartNote)}}"
[value]="cmpart.Id">{{cmpart.CompartTitle}}
</mat-option>
according to the #Sean solution I have update the code. But it doesn't set the value to the mat-select.
I have attached some pic of those mat-select.
Edit: Sorry - misunderstood. You want the value selected when there is only one option (default behavior), otherwise leave blank when 2+ options are available. Add an additional mat-option outside of your ngFor only when the ngFor expression returns more than 1 item.
<mat-form-field>
<mat-select (selectionChange)="CompartSelected($event, element, cmpart)" disableRipple [value]="element.Compart.Id" name="cmpart" >
<mat-option *ngIf="getAvailableCompartList(element.Compart.CompartType.Id).length > 1" value="">-- Please Select an Option --</mat-option>
<mat-option *ngFor="let cmpart of getAvailableCompartList(element.Compart.CompartType.Id)" title="{{Translate(cmpart.CompartNote)}}"
[value]="cmpart.Id">{{cmpart.CompartTitle}}
</mat-option>
</mat-select>
</mat-form-field>
You can clean this up a little by placing the function call to getAvailableCompartList inside your component so you're not eval'ing the function twice as the template is rendered.
In case someone still looking for a hint.
Normally when your select vary the size, means it is coming from an observable.
So you could do this:
Typescript code:
//HERE IS THE FUNCTION THAT LOADS YOUR OPTIONS. IN THIS CASE 'val' IS MY API RETURN.
//IN CASE SIZE IS 1, PASS THE FIRST VALUE TO YOUR VARIABLE MODEL.
loadParameter(){
this.service.getParameters().subscribe((val: any) => {
this.parameters = val;
if (val.length == 1) {
this.selectedParameter = val[0].ParameterId;
}
});
}
----------------------------------------------------------------------------
Here the front code:
<mat-label>Example</mat-label>
<mat-select [(ngModel)]="selectedParameter">
<mat-option *ngFor="let parameter of parameters" [value]="parameter.ParameterId">{{parameter.ParameterValue}}</mat-option>
</mat-select>
------------------------------------------------------------------------
I have a simple form which operates on the logic of:
Select Box 1 (Yes/No)
Select Box 2 (Show if Yes)
Select Box 3 (Show if No)
Only the shown selection box should be set to required, the other is not required.
<mat-select placeholder='Show First Options' formControlName='b' [(ngModel)]="view">
<mat-option [value]="'first'">
First
</mat-option>
<mat-option [value]="'second'">
Second
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="view === 'first'">
<mat-select
placeholder='First Items'
formControlName='one'
[required]="view === 'first'">
<mat-option *ngFor="let item of items1" [value]="item">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="view === 'second'">
<mat-select
placeholder='Second Items'
formControlName='two'
[required]="view === 'second'">
<mat-option *ngFor="let item of items2" [value]="item">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>
This works fine for the first, default select box. However, when you change to the second box, the first box seems to keep its required validator.
I have written a demo to demonstrate this:
https://stackblitz.com/edit/angular-9eoffq
How can I ensure only the viewed select box is required?
Apologies for editing the demo provided as people were reviewing it which caused confusion, however I seemed to have solved it - the issue seemed to stem from the DOM re-rendering to remove the mat-form-field before removing the required tag. This meant that the form still had the required attribute.
The demo has been updated with the solution - I had to programatically remove the required validator and add it to the appropriate form control. Then I had to update the value and validity to clear the errors after the validators were changed.
this.form.valueChanges.subscribe(value => {
if(value.b === 'first') {
this.form.controls['one'].setValidators(Validators.required)
this.form.controls['two'].clearValidators()
} else {
this.form.controls['two'].setValidators(Validators.required)
this.form.controls['one'].clearValidators()
}
this.form.controls['one'].updateValueAndValidity({onlySelf:true})
this.form.controls['two'].updateValueAndValidity({onlySelf:true})
})
Instead of using ngModel you can instead make full use of your reactive form, and utilize the form controls. Also, by disabling and enabling fields they are either included/excluded from the form object, therefore also validations will not apply.
You could listen to valueChanges of form, but I like to avoid it since if you are having a large form, it will be fired excessively. But if you want to only listen to a specific control changes, you can also do that. I like a simple change event here though:
<mat-select formControlName='b' (change)="onChange()">
and then hiding/showing the other select:
<mat-form-field *ngIf="form.controls.b.value === 'first'">
<!-- -->
<mat-form-field *ngIf="form.controls.b.value === 'second'">
and the change event:
onChange() {
if(this.form.get('b').value === 'first') {
this.form.get('one').enable()
this.form.get('two').disable()
} else {
this.form.get('one').disable()
this.form.get('two').enable()
}
}
DEMO
With this, we need to remember that the disabled control(s) are excluded from the form object, if you want all values (disabled included), you need to call this.form.getRawValue()
Still some one is looking for another solution, this may help.
<mat-select placeholder='Show First Options' formControlName='b' [(ngModel)]="view" #optionsSelector>
<mat-option value="first"> First </mat-option>
<mat-option value="second"> Second </mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="optionsSelector.value === 'first'">
<mat-select placeholder='First Items' formControlName='one'>
<mat-option *ngFor="let item of items1" [value]="item">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="optionsSelector.value === 'second'">
<mat-select placeholder='Second Items' formControlName='two'>
<mat-option *ngFor="let item of items2" [value]="item">
{{item}}
</mat-option>
</mat-select>
</mat-form-field>