I generating dynamic drop-down based on my model and trying to set it's selected item same as data from model. I am doing all this in *ngFor loop. But first time after the page has loaded it is binding correct values to drop-down but once I click inside window it changes values in all drop-downs to same value and throws below error :
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed
after it was checked. Previous value: 'model:
d9cddd06-911a-4fea-9b87-f045362ede52'. Current value: 'model:
bd39b9a1-42f2-4db1-9639-953206062l67'
I have tried using Change Detector in ngOnInit,ngAfterViewInit and even in subscribe method where I am getting the model.
I have also tried using ngModelChange but no luck.
I am getting error on third line in below code:
[(ngModel)]="data.reportTypeTemplate[i].reportTemplateId"
I am not sure now how to fix this issue.
Has anyone faced this issue or know the solution for this.
Let me know if more information is required.
Below is my Code :
<div class="form-group" *ngFor = "let type of masterRTTList; let i = index">
<label for="reportType">{{type.reportTypeName}}*</label>
<select [(ngModel)]="data.reportTypeTemplate[i].reportTemplateId" //Here
*ngIf="data.reportTypeTemplate.length > 0"
class="form-control rounded-0" formControlName="reportType">
<option value = "">Select Template</option>
<option *ngFor="let template of type.reportTemplateName" [ngValue]="template.id">
{{template.name}}
</option>
</select>
</div>
ngOnInit(){
this.apiService.get(environment.api_url, 'GetReports/')
.subscribe(templates => {
this.masterRTTList = templates
});
}
Related
I want to set value of select field to the one specified in repairData property called reportShiftId, but it doesn't work. On the other hand if i make Shift object inside repairData and reference it with reportShift.id it works.
In not working code when i change repairData.reportShiftId which is ng model of select, select option does not change, but after i choose something manually in select, ngModel starts working properly.
Not working code:
export class RepairData {
reportShiftId: number;
...
}
-
<select class="form-control" name="shift" [(ngModel)]="repairData.reportShiftId">
<option *ngFor="let shift of shifts" [ngValue]="shift.id">{{shift.name}}</option>
</select>
Working code:
export class RepairData {
reportShift: Shift;
...
}
-
<select class="form-control" name="shift" [(ngModel)]="repairData.reportShift.id">
<option *ngFor="let shift of shifts" [ngValue]="shift.id">{{shift.name}}</option>
</select>
How to use reportShiftId(number) instead of reportShift.id(Shift.number)?
Try to implement an compareWith function like so :
<select class="form-control" name="shift" [compareWith]="compareWithFunction" [(ngModel)]="repairData.reportShiftId">
<option *ngFor="let shift of shifts" [ngValue]="shift.id">{{shift.name}}</option>
</select>
compareWithFunction(item1,item2){
return item1 && item2 ? item1.id === item2.id : item1 === item2;
}
I know what the problem was.
After i changed name html attribute from shift to reportShift (the same name as object property) it started working.
Actually i think i had more than one select with the same name so that could be the problem.
I populating a select dropdown in Angular 6 from data returned from a resolver. Im subscribing to this.route.data and storing the data 'teamMembers' in an array.
Then i iterate over the array in my template with:
<div class="form-group" [ngClass]="{'highlighted' : messageForm.controls.MessageTo.disabled === false}" required>
<label>To</label>
<select class="form-control" formControlName="MessageTo" required>
<option [ngValue]="member" *ngFor="let member of teamMembers">{{ member.User.EmailID }}</option>
</select>
</div>
Im prepopulating the select with data returned from API with:
this.messageForm = this.fb.group({
MessageTo: [{value: this.thisMessage.ToUser.EmailID, disabled: false}]
});
I can see the data in the select dropdown in the browser, BUT ONLY once i click on the select. If I dont click on the select then it just shows blank as though nothing is in the select???
I want it to show the prepopulated Email set in the component.ts file.
Any help greatly appreciated.
Ah, sorted it. I added a new property of "originator" which was equal to the value of my default teamMemberGuid, to my class, and bound the value of that via [(ngModel)]="originator" on my select. Works a treat
What I'm using
angular
firebase
Currently, a standard HTML select component
What I'm trying to achieve
When a user is filling out some details in some inputs, I have a drop down containing a number of options
I want to have a default option selected (not a placeholder, an actual selection)
Question
As I'm looping through an array (ngFor), how do I apply a 'selected' attribute to one of the options? Let's say for example that the array contained 'album 1', 'album 2'and 'album 3'. By default, I want 'album 2' to be automatically selected.
<select #selectedAlbum>
<option *ngFor="let album of albumList" [value]="folder.folder_title">{{album.album.title}}</option>
</select>
You can bind your select element to an ngModel and then on the initialisation of your component set the ngModel to be your desired default value and the option will be selected for you by the two way binding provided by ngModel.
i.e.:
<select #selectedAlbum [(ngModel)]="mySelectedItem">
and in your component:
mySelectedItem: string;
ngOnInit() {
this.mySelectedItem = 'album 2';
}
You can add a selected attribute:
example using a predefined item
<select #selectedAlbum>
<option *ngFor="let album of albumList" [value]="folder.folder_title" [selected]="ablum.ablum.title === 'album 2'">{{album.album.title}}</option>
</select>
example using an index
<select #selectedAlbum>
<option *ngFor="let album of albumList; let i = index;" [value]="folder.folder_title" [selected]="i === 1">{{album.album.title}}</option>
</select>
Note:
This method does not use two-way binding. This is a one-way binding as you currently have implemented. If you'd prefer to use two-way binding (which is much more elegant in general) I'd highly recommend digging deeper into form models.
I have a simple dropdown that is populated from an array.
Users will be editing a record in a form where the priority of the record can be selected from the mentioned dropdown. I'm having difficulty with setting the selected item in that dropdown.
Here's my code for that dropdown:
<select *ngIf="formModel" [(ngModel)]="record.priority" formControlName="priority">
<option value="-1">Select priority</option>
<option *ngFor="let priority of formModel.priorities"
[ngValue]="priority"
[innerHtml]="priority.name"
[selected]="priority.id == record.priority.id"></option>
</select>
The selected priority of the record is however not selected, the resulting HTML shows selected="true".
When I change the code to the following:
[selected]="(priority.id == record.priority.id ? '' : null)"
The result is selected="", but the option is stil NOT selected.
I have already confirmed that that particular option should be selected.
Also when I change the HTML in Firebug to just selected the option is selected.
So my question is: how can I add an attribute on a certain condition so that the attribute is not added to other elements with an empty value?
Using two-way-binding is discouraged in reactive forms. The point is to utilize the form controls instead. Why use reactive form, if you are using two-way-binding? That would mean the model driven form is totally redundant. So if you want to solve this problem using the model-driven form, I'd suggest the following:
Since you are using a separate object (record.priority) it cannot automatically be bound as the pre-selected value, you'd have to somehow create a reference. So when building a form you can do this:
this.myForm = this.fb.group({
priority: [this.formModel.priorities.find(x => x.id == this.record.priority.id)]
});
And the template would look like this:
<form [formGroup]="myForm">
<select *ngIf="formModel" formControlName="priority">
<option value="-1">Select priority</option>
<option *ngFor="let priority of formModel.priorities"
[ngValue]="priority"
[innerHtml]="priority.name"></option>
</select>
</form>
Now the value object you are getting from the form holds this value.
if having the record coming async, you can set a boolean flag to not show the form until the values have been set. Or you can build an empty form initially and then use setValue() for the form control.
DEMO
EDIT: Looking closer, that you want to have the condition to set null if there is no value for record.priority? That can be done well in the form control as well:
priority: [this.record.priority ? this.formModel.priorities.find(x => x.id == this.record.priority.id) : null]
Try this :
<select *ngIf="formModel" [(ngModel)]="record.priority.id" formControlName="priority">
<option value="-1">Select priority</option>
<option *ngFor="let priority of formModel.priorities"
[ngValue]="priority.id"
[innerHtml]="priority.name"></option>
</select>
[ngValue]="priority.id" and [(ngModel)]="record.priority.id" should point to the same value , and it will work automatically ,
There is no need to write [selected]="priority.id == record.priority.id"
I have researched many similar existing answers on SO and elsewhere, but just can't find the solution to this.
I'm using the model-driven approach in Angular 2 to build my form, which is both an add and edit form. When in edit mode, the values are populated with data retrieved from a service: this aspect is all fine because the simple text inputs all bind correctly.
One of the properties is 'Country' and this is an object as follows:
export class Country {id: number; name: string;}
I want to bind this to a select control which will have the list of countries available, and the one from the model populated when the form loads. I want the value of the binding to be the country object, not just the id.
Here's the html of the select control:
<select class="form-control" id="country" formControlName="country">
<option value="default">--Select a country--</option>
<option *ngFor="let c of countries" [value]="c">{{c.name}} </option>
</select>
And here is where i try to to populate the value from the component class:
(<FormControl>this.personForm.controls['country'])
.setValue(this.person.country, { onlySelf: true });
But there is no selected option when the page loads, even though the console confirms that this.person.country exists and is populated with the correct object.
I can get it working with ids: changing to [value]="c.id" in the view and appending .id in the class, and then it works in that the right option is selected. The problem is that the select no longer emits an object for the country property, just the id. I tried changing [value] to [ngValue] and get the same result. I even added [ngModel]="country" to the select element and that didn't help either.
I'd be grateful for any help.
The issue is most likely that this.person.country is not the same country as in your countries array.
If we want to make them the same we can either explicitly subscribe to the valueChanges of the select control or bind [(ngModel)] to person.country:
subscribe to changes
code
this.countryForm.controls['country'].valueChanges.subscribe(country =>
this.person.country = country;
);
// initialize by finding the correct country object (this will overwrite the person's country object)
this.countryForm.controls['country'].setValue(countries.filter(c => c.id === person.country.id));
template
ngModel bind
We still have to make the objects match (compare strategy that Angular 2 uses which is really what JS uses)
code
this.person.country = this.countries.filter(c => c.id === this.person.country.id)[0];
template
<select class="form-control" id="country" formControlName="country" [(ngModel)]="person.country">
<option value="default">--Select a country--</option>
<option *ngFor="let c of countries" [ngValue]="c">{{c.name}}</option>
</select>
ngModel Plunker: http://plnkr.co/edit/UIS2V5rKh77n4JsjZtii?p=preview
subscription Plunker: http://plnkr.co/edit/yyZ6ol1NPD77nyuzwS2t?p=info