Nothing selected in Select by default - how to fix that? - html

I'm using Angular 5 and I have a simple Select:
<select class="ui fluid dropdown" formControlName="device">
<option *ngFor="let device of getSenderDevices()" [ngValue]="device">{{device.Name}}</option>
</select>
My problem is the fact that by default nothing is selected, but I'd like the first option to be selected. I saw many threads like this, the solution that I thought would work, does not:
<select class="ui fluid dropdown" formControlName="device">
<option *ngFor="let device of getDevices(); let i = index" [ngValue]="device" [selected]="i==0">{{device.Name}}</option>
</select>
I also found some advices to use compareWith directive - but I wasn't able to understand how it works.
Maybe the problem is caused by getDevices(), which returns data with some delay, because the data is fetched from external server. In the beginning select has to be empty, because the data is not ready yet. When it arrives however, I'd like the select to show that by auto-selecting first option.

Not use a function getDevices() and not use [selected] in .html
//I imagine you have a serviceData that return an observable
export class DataService {
constructor(private httpClient HttpClient) {}
public getDevices():Observable<any>
{
return this.httpClient.get("....");
}
}
constructor(private fb:FormBuilder,private myservice:ServiceData){}
ngOnInit()
{
this.myService.getDevices().subscribe(res=>{
this.devices=res;
this.createForm();
})
//If getDevices() simple return an array, not from service
// this.devices=getServices();
// this.createForm();
}
createForm()
{
this.myForm=this.fb.group({device:this.device[0]})
}
<form [formGroup]="myForm">
<select class="ui fluid dropdown" formControlName="device">
<!--NOT use [selected], when "device" get the value, the select show the value-->
<!--I use the variables "devices"--->
<option *ngFor="let device of devices; let i = index"
[ngValue]="device">{{device.Name}}</option>
</select>
</form>

Related

How to use object child as value in select without matching property name

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.

Angular changeable form according to inputs

I'm using a reactive form. I need to add/remove an input that appears in it according to some other input. Here's a simplified scenario of the issue:
Asking the user to select an option from a list. If their desired option is not there, there is an open input where they can write. If they do choose an option from the select, the input must disappear. If they do not select an option, the input must be there and it must be required.
Here's the code I made which 1) doesn't work 2) feels like it's fairly ugly and could be made in some other way.
Template:
<form [formGroup]="whateverForm" (ngSubmit)="onSubmit()">
Choose an option:
<select
formControlName="option"
(change)="verifySelection($event)">
<option value=''>None</option>
<option value='a'>Something A</option>
<option value='b'>Something B</option>
</select>
<br>
<div *ngIf="!optionSelected">
None of the above? Specify:
<input type="text" formControlName="aditional">
</div>
<br>
<br>
Form current status: {‌{formStatus}}
</form>
Code:
export class AppComponent {
whateverForm: FormGroup;
formStatus: string;
optionSelected = false;
ngOnInit() {
this.whateverForm = new FormGroup({
'option': new FormControl(null, [Validators.required]),
'aditional': new FormControl(null, [Validators.required])
});
this.whateverForm.statusChanges.subscribe(
(status) => {
this.formStatus = status;
}
);
}
verifySelection(event: any) {
if (event.target.value !== '') {
this.optionSelected = true;
this.whateverForm.get('aditional').clearValidators();
this.whateverForm.get('option').setValidators(
[Validators.required]);
} else {
this.optionSelected = false;
this.whateverForm.get('option').clearValidators();
this.whateverForm.get('aditional').setValidators(
[Validators.required]);
}
}
}
Instead of using an event, I used an observable in one of the fields. The exact solution to the problem I proposed is here.
And I solved it using what I found here (they are basically the same thing, but I included mine for completion).

Model is changing automatically in angular 6

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
});
}

ReactiveForm for dynamically updated form entries

How to check status of myform in component to check if all the fields are filled or not?
HTML:
<div [formGroup]="myform">
<div *ngFor="let question of questions">
<label>{{question.question}}</label>
<select required >
<option selected disabled="disabled">Option</option>
<option *ngFor="let option of question['options']">{{option}}</option>
</select>
</div>
</div>
</div>
Question JSON coming from API:
this.questions = [
{
question: 'What is your age?',
options: ['20', '30', '40']
},
{
question: 'How much quantity?',
options: ['1','2','3']
}]
If you use ReactiveForm, you need use a FormArray
A FormArray can be of FormControl or a FormGroup
FormArray of FormControls
constructor(private fb:FormBuilder) {}
ngOnInit() {
//We create an array of FormControl, each question a FormControl
let data:FormControl[]=this.questions.map(q=>new FormControl());
this.myform=this.fb.group({
questions:new FormArray(data)
})
}
//the .html
<!--we use *ngIf to show the form only when we create the form-->
<div *ngIf="myform" [formGroup]="myform">
<!--we iterate to myForm.get('questions').controls -->
<!--we use our variable "questions" to show the label and options-->
<div *ngFor="let question of myform.get('questions').controls;let i=index">
<label>{{questions[i].question}}</label>
<select required [formControl]="question" >
<option value="null" disabled="disabled">Option</option>
<option *ngFor="let option of questions[i].options">{{option}}</option>
</select>
</div>
</div>
<!--just for check-->
{{myform?.value |json}}
If we use an array of formGroup we change some things
constructor(private fb:FormBuilder) {}
ngOnInit() {
//we create and array of FormGroup
let data2:FormGroup[]=this.questions.map(q=>this.fb.group({
option:null
}));
this.myform2=this.fb.group({
questions:new FormArray(data2)
})
}
<div *ngIf="myform2" [formGroup]="myform2">
<!--see that we say to Angular the "formArrayName" -->
<div formArrayName="questions">
<div *ngFor="let question of myform2.get('questions').controls;
let i=index" [formGroupName]="i"> <!--don't forget formGroupName-->
<label>{{questions[i].question}}</label>
<!--the select use formControlName, our array is an array of FormGroup-->
<select required formControlName="option" >
<option value="null" disabled="disabled">Option</option>
<option *ngFor="let option of questions[i].options">{{option}}</option>
</select>
</div>
</div>
</div>
{{myform2?.value |json}}
Aclaration:#FrontEndDeveloper. One thing is the array question that we use to make the questions.(Perhafs I must be choose other names to the variables), other thing is the value of the form. The value of myform1={questions:["20","1"]}, the value of myform2={questions:[{option:"20"},{option:"2"}]}.
When we create an array of FormControl (or an array of FbGroup) I used map, equally I can do some like
let data:FormControl[]=[];
data.push(new FormControl());
data.push(new FormControl());
or
let data2:FormGroup[]=[];
data2.push(this.fb.group({
option:null
}));
data2.push(this.fb.group({
option:null
}));
Generally we have some data to initialize the form. (an object with some data) that we get from a dbs
//Imagine we have mydata{name:"A",options=["20","1"]}
//we can map this data to create the form
let data:FormControl[]=this.mydata.options.map(q=>new FormControl(q));
//or
let data2:FormGroup[]=this.mydata.options.map(q=>this.fb.group({
option:q
}));
//Imagine we have mydata{name:"A",options=[{option:"20"},{option:"1"}]}
//we can map this data to create the form
let data:FormControl[]=this.mydata.options.map(q=>new FormControl(q.option));
//or
let data2:FormGroup[]=this.mydata.options.map(q=>this.fb.group({
option:q.option
}));
This would help you to understand reactive form basic functionalities.
https://stackblitz.com/edit/objects-equality-check-edhyk5?file=src/app/app.component.ts
It will help to understand:
1. FormBulder,
2. FormGroup,
3. Form Value changes etc.

Fill in dropdown from json table

So ...i have url (say... http://localhost:8080/website/country) that I target to get this list:
What i want is to populate dropdown with list of county names so user can pick one.
I also did dropdown in html
I am using Angular 2, i have service in which I set to get url from database
I'm sure that I have mistake, so need help :D Thanks
Edit: this is component, if could help
EDIT:
It seems that there is trouble in your component.
First of all, you have to trigger the request which will retrieve the countries and assign the response.
It will looks like following (note we assign the Observable):
#Component(...)
export class CompanyTemplatePopupComponent {
countries;
ngOnInit(){
countries = this.companyService.getCountries();
// or whichever method you need to retrieve the list of countries
}
}
Then in your template (note the use of async pipe):
<option *ngFor="let country of countries | async" [value]="country.id"> {{ country.name }} </option>
html code will be
<select #countriesSelect class=custom-dropdown">
<option selected disabled>Select Country</option>
<option *ngFor="let country of countries: [value]="country.id">{{country.name}}</option>
</select>
In ts code you have to getAllCountries() method in constructor or ngOnInit(). getAllCountries() is a method to fill the data of countries to dropdown list
getAllCountries() {
this.getHttp().get(this.url)
.map( (response) => {
this.countries = response;
console.log(response); // To check countries is coming or not!
})
}