I have three matformfields named Form A,Form B,Form C and three mat radio buttons named A,B,C.
What I want is that when radiobutton A is enabled or checked Form A's default value should be A and in other two form fields there should be no value by default. When radiobutton B is enabled or checked Form B's default value should be B and in other two form fields there should be no value by default.I want the same for radiobutton C. I am getting the dropdown data from service.
Sample data:
listes: any[] = [
{ id: 1, name: "A" },
{ id: 2, name: "B" },
{ id: 3, name: "C" },];
WHAT I HAVE TRIED:
I tried to get the id 1 which has value A and used setvalue to patch it in Form A but its not worling
const toSelect = this.listes.find(c => c.id == 1);
this.patientCategory.get('patientCategory').setValue(toSelect);
STACKBLITZ: https://stackblitz.com/edit/how-to-set-default-value-of-mat-select-when-options-are-reo3xn?file=app%2Ftable-basic-example.html
I've corrected your code as per the scenario you described. Although my temporary code is a little lengthy, it applies the logic you described. But I hope you simplify it further.
Fix:
[value] attribute of a mat-option shouldn't be set to category itself as category is an object. [value] expects a singular uniquely identifying value. So you should set it to [value] = "category.name". Ideally, we set value to unique identifiers like [value]="category.id" or [value]="category.key" etc.
The three mat-selects should behave independently in your scneario. So they should never be assigned to the same formControl. Instead, assign individual formControls to have full control over them.
Finally, you can use the function valueChange assigned to the radio buttons, to conditionally apply values in FormA, FormB and FormC as per your scenario.
<form [formGroup]="patientCategory">
<mat-form-field class="full-width">
<mat-select placeholder="FORMA" formControlName="patientCategoryA">
<mat-option *ngFor="let category of listes" [value]="category.name">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<mat-select placeholder="FORMB" formControlName="patientCategoryB">
<mat-option *ngFor="let category of listes" [value]="category.name">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="full-width">
<mat-select placeholder="FORMC" formControlName="patientCategoryC">
<mat-option *ngFor="let category of listes" [value]="category.name">
{{category.name}}
</mat-option>
</mat-select>
</mat-form-field>
</form>
<div class="container" style="margin-top: 0px;">
<div class="example-container">
<mat-radio-group #group="matRadioGroup" [(ngModel)]="test" [(value)]="selectedValue"
(change)="onValueChange(group.value)">
<mat-radio-button value="A" [checked]="defaultSelected">A</mat-radio-button>
<mat-radio-button style="margin-left:10px" value="B">B</mat-radio-button>
<mat-radio-button style="margin-left:10px" value="C">C</mat-radio-button>
</mat-radio-group>
</div>
</div>
import { Component, ViewChild } from "#angular/core";
import {
FormBuilder,
FormGroup,
FormControl,
Validators
} from "#angular/forms";
import { DataService } from "./data.service";
/**
* #title Basic table
*/
#Component({
selector: "table-basic-example",
styleUrls: ["table-basic-example.css"],
templateUrl: "table-basic-example.html"
})
export class TableBasicExample {
patientCategory: FormGroup;
listes: any[];
constructor(private fb: FormBuilder, private dataService: DataService) {}
ngOnInit() {
this.dataService.getData().subscribe(res => {
this.listes = res;
});
this.patientCategory = this.fb.group({
patientCategoryA: [null, Validators.required],
patientCategoryB: [null, Validators.required],
patientCategoryC: [null, Validators.required]
});
}
onValueChange(value) {
if (value === "A") {
this.patientCategory.get("patientCategoryA").setValue(value);
this.patientCategory.get("patientCategoryB").setValue(null);
this.patientCategory.get("patientCategoryC").setValue(null);
} else if (value === "B") {
this.patientCategory.get("patientCategoryB").setValue(value);
this.patientCategory.get("patientCategoryA").setValue(null);
this.patientCategory.get("patientCategoryC").setValue(null);
} else if (value === "C") {
this.patientCategory.get("patientCategoryC").setValue(value);
this.patientCategory.get("patientCategoryB").setValue(null);
this.patientCategory.get("patientCategoryA").setValue(null);
}
}
}
Hope this helps. Let me know if you have any issues.
Related
<mat-select [(ngModel)]="textList" >
<mat-option *ngFor="let textof list" [value]="text">
{{ text }}
</mat-option>
<mat-form-field class="example-full-width">
<input matInput [(ngModel)]="holdReason"/>
</mat-form-field>
</mat-select>
using this code I can show a input field inside the mat-select. but if give some values to that input field that value is not appear in the box. it is empty. Is it possible to just show the text that we entered in input box show inside mat-select
This is what i can see after enter something in the input and just press enter
Here is a working version, you can refer the below stackblitz, do let me know if any doubts. You can enter a new value by giving enter key.
ts
import { ViewChild } from '#angular/core';
import { ElementRef } from '#angular/core';
import { Component } from '#angular/core';
import { MatSelect } from '#angular/material/select';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
#ViewChild('matSelect') matSelect: ElementRef<MatSelect> | MatSelect;
public variables = ['One', 'Two', 'County', 'Three', 'Zebra', 'XiOn'];
public variables2 = [
{ id: 0, name: 'One' },
{ id: 1, name: 'Two' },
];
selected = null;
public filteredList1 = this.variables.slice();
public filteredList2 = this.variables.slice();
public filteredList3 = this.variables.slice();
public filteredList4 = this.variables.slice();
public filteredList5 = this.variables2.slice();
enter(e) {
const matSelect: MatSelect =
this.matSelect && (<ElementRef<MatSelect>>this.matSelect).nativeElement
? <MatSelect>(<ElementRef<MatSelect>>this.matSelect).nativeElement
: <MatSelect>this.matSelect;
// console.log(this.matSelect);
const value = e.target && e.target.value;
if (value && matSelect) {
e.target.value = '';
this.variables.push(value);
this.filteredList1 = this.variables;
this.selected = value;
matSelect.close();
}
}
}
html
<div class="center">
<mat-form-field>
<mat-select placeholder="Basic" #matSelect [(ngModel)]="selected">
<mat-select-filter
[array]="variables"
(filteredReturn)="filteredList1 = $event"
(keydown.enter)="enter($event)"
></mat-select-filter>
<mat-option *ngFor="let item of filteredList1" [value]="item">
{{ item }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
forked stackblitz
I would like to know if there is a possible way to disable certain checkbox items that is present in the multiselect dropdown. The multiselect has an option to disable the whole dropdown but I would like to know if we can disable particular checkboxes. For the below code, is there a way to disable the default selected checkbox values.
TS
import { Component, OnInit } from '#angular/core';
export class AppComponent implements OnInit {
dropdownList = [];
selectedItems = [];
dropdownSettings = {};
ngOnInit(){
this.dropdownList = [
{"id":1,"itemName":"India"},
{"id":2,"itemName":"Singapore"},
{"id":3,"itemName":"Australia"},
{"id":4,"itemName":"Canada"},
{"id":5,"itemName":"South Korea"},
{"id":6,"itemName":"Germany"},
{"id":7,"itemName":"France"},
{"id":8,"itemName":"Russia"},
{"id":9,"itemName":"Italy"},
{"id":10,"itemName":"Sweden"}
];
this.selectedItems = [
{"id":2,"itemName":"Singapore"},
{"id":3,"itemName":"Australia"},
{"id":4,"itemName":"Canada"},
{"id":5,"itemName":"South Korea"}
];
this.dropdownSettings = {
singleSelection: false,
text:"Select Countries",
selectAllText:'Select All',
unSelectAllText:'UnSelect All',
enableSearchFilter: true,
classes:"myclass custom-class"
};
}
onItemSelect(item:any){
console.log(item);
console.log(this.selectedItems);
}
OnItemDeSelect(item:any){
console.log(item);
console.log(this.selectedItems);
}
onSelectAll(items: any){
console.log(items);
}
onDeSelectAll(items: any){
console.log(items);
}
}
HTML
<angular2-multiselect [data]="dropdownList" [(ngModel)]="selectedItems"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
(onDeSelect)="OnItemDeSelect($event)"
(onSelectAll)="onSelectAll($event)"
(onDeSelectAll)="onDeSelectAll($event)"></angular2-multiselect>
in dropdownList: you can add additional key to options you want to disable, like this:
{ id: 1, itemName: 'India', disabled: true }
and then in html use custom Template like this:
<angular2-multiselect [data]="dropdownList" [(ngModel)]="selectedItems"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
(onDeSelect)="OnItemDeSelect($event)"
(onSelectAll)="onSelectAll($event)"
(onDeSelectAll)="onDeSelectAll($event)">
<c-badge>
<ng-template let-item="item">
<label style="color: #333;min-width: 150px;">{{item.itemName}}</label>
[disabled]="item.disabled"
</ng-template>
</c-badge></angular2-multiselect>
Here is the working example:
https://stackblitz.com/edit/angular2-multiselect-dropdown-tsqghc?file=src%2Fapp%2Fapp.component.html
You can disable a specific options from the template by using : [disabled] inside the options.
for example:
<mat-form-field appearance="fill">
<mat-label>Choose an option</mat-label>
<mat-select [disabled]="disableSelect.value">
<mat-option value="option1">Option 1</mat-option>
<mat-option value="option2" disabled>Option 2 (disabled)</mat-option>
<mat-option value="option3">Option 3</mat-option>
</mat-select>
</mat-form-field>
from Angular Material Select
as you can see in option 2 you have the "disabled" , you can change it to input and pass it from your list or just set disabled for the first option.
you can add the HTML file and then I can edit and add the full code.
i create this dropdown component :
<mat-form-field appearance="outline">
<mat-label>{{formTitle| translate}} *</mat-label>
<mat-select [(value)]="itemId">
<div class="col-lg-12 mt-4 kt-margin-bottom-20-mobile">
<mat-form-field class="mat-form-field-fluid" appearance="outline">
<mat-label>{{'GENERAL.TITLE' | translate}} *</mat-label>
<input (keyup)="getValues($event.target.value)" matInput [placeholder]="'GENERAL.TITLE' | translate">
</mat-form-field>
</div>
<mat-progress-bar *ngIf="loading" class="mb-2" mode="indeterminate"></mat-progress-bar>
<mat-option (click)="emitdata(item.key)" *ngFor="let item of values" [value]="item.key">
{{item.value}}
</mat-option>
</mat-select>
ts:
export class SearchableDropdownComponent implements OnInit {
#Input() url: string;
#Input() formTitle: string;
#Output() selectedId = new EventEmitter<number>();
#Input() itemId: number;
loading = false;
values: KeyValue[];
title: string;
constructor(
private searchService: SearchableDropDownService,
private cdRef: ChangeDetectorRef) {
}
ngOnInit(): void {
this.getValues(null);
}
emitdata(event): void {
console.log(event);
this.selectedId.emit(event);
}
getValues(event): void {
this.cdRef.detectChanges();
this.loading = true;
let model = {} as SendDateModel;
model.page = 1;
model.pageSize = 60;
model.title = event;
this.searchService.getAll(this.url, model).subscribe(data => {
this.values = data['result']['records'];
this.cdRef.detectChanges();
this.loading = false;
});
}
}
and i used it in components :
<div class="col-lg-6 kt-margin-bottom-20-mobile">
<kt-searchable-dropdown [itemId]="304" [formTitle]="'COURSE.COURSE_GROUP'" [url]="url"></kt-searchable-dropdown>
</div>
i pass to dropdown 304 item for pre selected it in dropdown . but it not pre-selected item 304 in dropdown .
how can i set the 304 item selected in dropdown?
As you are taking the ItemId using Input() you can always use ngModel to implement two way data binding.
For e.g. in your case :
<mat-select [(ngModel)]="ItemId">
<mat-option *ngFor="let item of values" [value]="item.key">{{item.value}}</mat-option>
</mat-select>
So, basically it will get binded in two way with variable contain data and will remain selected as you load the component.
You can read more about two way data binding here.
Update
ngModel should work. You have not wrongly implemented but its not correct way also.
Your selected value only will come from [(ngModel)].
so your
[(value)]="itemId"
should be
[(ngModel)]="itemId"
complete code will be :
<mat-select [(ngModel)]="ItemId">
<mat-option *ngFor="let item of values" [value]="item.key">{{item.value}}</mat-option>
</mat-select>
Try not to declare any div or component after mat-select if not necessary or debug one by one if its bugging to your component or not.
I am trying to add a form field with custom telephone number input control. I used the example of the phone from https://material.angular.io/components/form-field/examples.
Here is the code:
<mat-form-field>
<example-tel-input placeholder="Phone number" required></example-tel-input>
<mat-icon matSuffix>phone</mat-icon>
<mat-hint>Include area code</mat-hint>
</mat-form-field>
import {FocusMonitor} from '#angular/cdk/a11y';
import {coerceBooleanProperty} from '#angular/cdk/coercion';
import {Component, ElementRef, Input, OnDestroy} from '#angular/core';
import {FormBuilder, FormGroup} from '#angular/forms';
import {MatFormFieldControl} from '#angular/material';
import {Subject} from 'rxjs';
/** #title Form field with custom telephone number input control. */
#Component({
selector: 'form-field-custom-control-example',
templateUrl: 'form-field-custom-control-example.html',
styleUrls: ['form-field-custom-control-example.css'],
})
export class FormFieldCustomControlExample {}
/** Data structure for holding telephone number. */
export class MyTel {
constructor(public area: string, public exchange: string, public subscriber: string) {}
}
/** Custom `MatFormFieldControl` for telephone number input. */
#Component({
selector: 'example-tel-input',
templateUrl: 'example-tel-input-example.html',
styleUrls: ['example-tel-input-example.css'],
providers: [{provide: MatFormFieldControl, useExisting: MyTelInput}],
host: {
'[class.example-floating]': 'shouldLabelFloat',
'[id]': 'id',
'[attr.aria-describedby]': 'describedBy',
}
})
export class MyTelInput implements MatFormFieldControl<MyTel>, OnDestroy {
static nextId = 0;
parts: FormGroup;
stateChanges = new Subject<void>();
focused = false;
ngControl = null;
errorState = false;
controlType = 'example-tel-input';
id = `example-tel-input-${MyTelInput.nextId++}`;
describedBy = '';
get empty() {
const {value: {area, exchange, subscriber}} = this.parts;
return !area && !exchange && !subscriber;
}
get shouldLabelFloat() { return this.focused || !this.empty; }
#Input()
get placeholder(): string { return this._placeholder; }
set placeholder(value: string) {
this._placeholder = value;
this.stateChanges.next();
}
private _placeholder: string;
#Input()
get required(): boolean { return this._required; }
set required(value: boolean) {
this._required = coerceBooleanProperty(value);
this.stateChanges.next();
}
private _required = false;
#Input()
get disabled(): boolean { return this._disabled; }
set disabled(value: boolean) {
this._disabled = coerceBooleanProperty(value);
this.stateChanges.next();
}
private _disabled = false;
#Input()
get value(): MyTel | null {
const {value: {area, exchange, subscriber}} = this.parts;
if (area.length === 3 && exchange.length === 3 && subscriber.length === 4) {
return new MyTel(area, exchange, subscriber);
}
return null;
}
set value(tel: MyTel | null) {
const {area, exchange, subscriber} = tel || new MyTel('', '', '');
this.parts.setValue({area, exchange, subscriber});
this.stateChanges.next();
}
constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>) {
this.parts = fb.group({
area: '',
exchange: '',
subscriber: '',
});
fm.monitor(elRef, true).subscribe(origin => {
this.focused = !!origin;
this.stateChanges.next();
});
}
ngOnDestroy() {
this.stateChanges.complete();
this.fm.stopMonitoring(this.elRef);
}
setDescribedByIds(ids: string[]) {
this.describedBy = ids.join(' ');
}
onContainerClick(event: MouseEvent) {
if ((event.target as Element).tagName.toLowerCase() != 'input') {
this.elRef.nativeElement.querySelector('input')!.focus();
}
}
}
example-tel-input-example.html
<div [formGroup]="parts" class="example-tel-input-container">
<input class="example-tel-input-element" formControlName="area" size="3">
<span class="example-tel-input-spacer">–</span>
<input class="example-tel-input-element" formControlName="exchange" size="3">
<span class="example-tel-input-spacer">–</span>
<input class="example-tel-input-element" formControlName="subscriber" size="4">
</div>
But I get the following error:
ERROR Error: mat-form-field must contain a MatFormFieldControl.
Need to import two module and add those in imports and exports section.
import { MatFormFieldModule } from '#angular/material/form-field';
import { MatInputModule } from '#angular/material/input';
#NgModule ({
imports: [ MatFormFieldModule, MatInputModule ],
exports: [ MatFormFieldModule, MatInputModule ]
})
And the most thing which everybody miss this '/' character. if you see the Angular Material Documentation , they also miss this (Last Checked 16 Jun 2020, don't know they even updated or not). I make an example for clarifications
<!-- Wrong -->
<mat-form-field>
<input matInput>
</mat-form-field>
<!-- Right -->
<mat-form-field>
<input matInput />
</mat-form-field>
Look at the snippet carefully. when <input begin it must close with /> but most people miss the / (backslash) character.
Make sure MatInputModule is imported and <mat-form-field> contains <input> with matInput / matSelect directives.
https://github.com/angular/material2/issues/7898
Import MatInputModule, solved my error
You need to specify your class as a provider for MatFormFieldControl
https://material.angular.io/guide/creating-a-custom-form-field-control#providing-our-component-as-a-matformfieldcontrol
#Component({
selector: 'form-field-custom-control-example',
templateUrl: 'form-field-custom-control-example.html',
styleUrls: ['form-field-custom-control-example.css'],
providers: [
{ provide: MatFormFieldControl, useExisting: FormFieldCustomControlExample }
]
})
Also, don't forget to write the name attribute in the input tag:
name="yourName"
if you are using any 'input' tag in your code along with 'mat-form-field', make sure to include 'matInput' in the input tag
if there is any *ngIf present in child tag of 'mat-form-field', specify the *ngIf condition in 'mat-form-field' tag
Another possible issue closing the input tag. If you copy code from one of the Angular examples (https://material.angular.io/components/datepicker/overview), you may end up with the code:
<mat-form-field appearance="fill">
<mat-label>Choose a date</mat-label>
<input matInput [matDatepicker]="picker">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
The input should have the close tag (slash):
<input matInput [matDatepicker]="picker" />
This will fix your issue
import {
MatFormFieldModule,
MatInputModule
} from "#angular/material";
Error says that mat-form-field should contain at least one form field from which input is taken.
Ex : matInput mat-select etc.
In your case you may add matInput tag to your input fields within example-tel-input-example.html. And also you could move mat-form-field inside example-tel-input-example component and add it against each matInput field.
<div [formGroup]="parts" class="example-tel-input-container">
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="area" size="3">
</mat-form-field>
<span class="example-tel-input-spacer">–</span>
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="exchange" size="3">
</mat-form-field>
<span class="example-tel-input-spacer">–</span>
<mat-form-field>
<input matInput class="example-tel-input-element" formControlName="subscriber" size="4">
</mat-form-field>
</div>
Note : mat-icon or mat-hint cannot be considered as form-fields
I have my interface like this
export interface IFilterParams {
columnTitle: string;
key: string;
mode: FILTER_MODE;
compareMethod: COMPARE_METHOD;
keyToCheck?: string;
sliderKeys?: string[];
startingValue?: number;
placeHolder?: string;
cssClass?: string;
formControl?: string;
}
which I use to create html (filter form) like below
<div [ngClass]="(filter.cssClass || 'col-md-4') + 'mt-2 pt-1'">
<div class="filter-key-label">
{{filter.columnTitle}}
</div>
<div class="filter-form-control d-flex flex-wrap justify-content-left">
<mat-form-field class="full-width">
<input type="text" matInput [formControl]="filter.formControl" [matAutocomplete]="auto" (change)="handleEmptyInput($event, filter.key)">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of getOptionsTypeAhead(filter.key, filter.formControl) | async" [value]="option" (onSelectionChange)="typeaheadChange($event, filter.key)">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
Now as you can see, I am trying to bring in values from the filter variable (look at how I am passing filter.key)
The thing is, I am unable to pass a variable value to [formControl] as it's throwing me
TypeError: Cannot create property 'validator' on string 'country' at setUpControl
for
{
key: 'country',
mode: FILTER_MODE.AUTOCOMPLETE,
columnTitle: 'Country',
compareMethod: COMPARE_METHOD.ONE_TO_ONE,
formControl: 'countryForm',
cssClass: ''
},
What am I doing wrong here? I want to use the same html to generate different forms with different form control names.
Update
This didn't work even after adding the direct string based variable in my component.ts file like this
countryForm: FormControl = new FormControl();
You are passing a string object to the formControl property with [formControl]="filter.formControl":
countryForm: FormControl = new FormControl();
filter = {
...
formControl: 'countryForm',
}
But you need to pass a FormControl object:
countryForm: FormControl = new FormControl();
filter = {
...
formControl: this.countryForm,
}