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.
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
in my app i display list of appeals, with their status (which is displayed using mat icon). Here is piece of my template
<div class="approve-detail" fxLayout="column" fxLayoutGap="10px">
<p>Created: {{absDetail?.reqDate|date:'d. L. y HH:mm'}}</p>
<ng-container *ngIf="absDetail?.defList">
<mat-list >
<mat-list-item class="def-item" *ngFor="let def of absDetail.defList">
<mat-icon matListIcon *ngIf="def.idReject!=0" class="warn" matTooltip="Rejected">thumb_down</mat-icon >
<mat-icon matListIcon *ngIf="def.idApprove!=0&&def.idReject==0" class="success" matTooltip="Approved">thumb_up</mat-icon>
<mat-icon matListIcon *ngIf="def.idReject==0 && def.idApprove==0" matTooltip="Waiting">help</mat-icon>
<p matLine>{{def.name}}</p>
</mat-list-item>
</mat-list>
<mat-list *ngIf="abs | isDeleteAppealed:absDetail.defList">
<mat-list-item class="def-item" *ngFor="let def of absDetail.defList">
<mat-icon matListIcon *ngIf="def.idCancel<0" color="warn" matTooltip="Rejected">thumb_down</mat-icon >
<mat-icon matListIcon *ngIf="def.idCancel>0" class="success" matTooltip="Approved">thumb_up</mat-icon>
<mat-icon matListIcon *ngIf="def.idCancel==0" matTooltip="waiting">help</mat-icon>
<p matLine>{{def.name}}</p>
</mat-list-item>
</mat-list>
</ng-container>
</div>
It works, but its kinda dirty with all that ng-ifs, is there any more elegant way to do this? I was thinking about pipe, but i need to generate three dynamic properties for each element: class, tooltip and proper icon name, so it doesnt seems like a better solution. Any ideas? What about some kind of directive?
One option you could do is wrap them in a separate component. Use your let def as an #Input() parameter. When it gets set, you can automatically change the value of the class/tooltip/icon. Something like this:
abs-icon.component.ts
imports...
#Component({
selector: 'abs-icon',
templateUrl: './abs-icon.component.html',
styleUrls: ['./abs-icon.component.css']
})
export class AbsIconComponent implements OnInit {
public cls: string;
public tooltip: string;
public icont: string;
private _abs: any;
get abs(): any{
return this._abs;
}
#Input() set abs(value: any) {
this._abs = value;
if (_abs.idReject != 0) {
cls = "warn";
tooltip = "Rejected";
icont = "thumb_down"
}
else if (.......do the rest){
/* some code */
}
}
constructor() { }
ngOnInit(): void { }
}
abs-icon.component.html
<mat-icon matListIcon
class="{{cls}}"
[matTooltip]="tooltip">
{{icon}}
</mat-icon >
using it:
<abs-icon [abs]="def"> </abs-icon>
I have angular code something like this: and I want to populate checkbox ticked for the option which are default selected
export class InformationComponent implements OnInit{
dataIds: FormControl;
#Input()
requestBody:Request;
requestForm: FormGroup;
constructor(private _formBuilder: FormBuilder){}
ngOnInit(){
this.dataIds = new FormControl(this.requestBody.dataIds);
this.requestForm = this._formBuilder.group({
dataIds: this.dataIds;
})
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<form [formGroup]="reqForm" #mainForm>
<div>
<app-data-list [dataIds]="dataIds" [disabled]="disabled"> </app-data-list>
</div>
</form>
and below is my app-data-list component
export class EntityListComponent implemments OnInit, OnDestroy{
#Input()
public disabled:boolean;
public entitiesFilter:FormControl = new FormControl();
protected entityList = new RequestEntity[];
#Input()
public dataIds:FormControl;
#ViewChild('multiSelect', {static:true}) multiselect:MatSelect;
protected _onDestroy = new Subject<void>();
public filteredEntityList:ReplaySubject<RequestEntity[]> = new ReplaySubject<RequestEntity[]>
ngOnInit(){
this.myservice.getData().subscribe((resp:RequestEntity[])=>{
entityList = resp;
})
this.filteredEntityList.next(this.entityList.slice());
this.entitiesFilter.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => { this.filterEntitiesList();});
}
ngAfterViewInit(){
this.setInitialValue();
}
setInitialValue(){
this.filteredEntitiesList.pipe(take(1), takeUntil(_onDestroy)).subscribe(() => {
this.multiSelect.compareWith =(a:RequestEntity, b:RequestEntity) => a && b && a.entity == b.entity;
})
}
}
<div [formGroup]="form">
<mat-form-field>
<mat-label> Data ids</mat-label>
<mat-select [formControl]="dataIds" [multiple]="true" #multiSelect [disabled]="disabled">
<ngx-mat-select-search [formControl]="entitiesFilter" placeholderLabel="Search">
</ngx-mat-select-search>
<mat-option *ngFor="let entity of filterdEntitiesList |async" [value]"entity"> {{entity?.entity?.entityName}} </mat-option>
</mat-select>
</mat-form-field>
</div>
but my code is not pre populating the checked option against selected dataIds from back end but I had similar snippet in my code which does exactly same thing
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.
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,
}