I'm trying to create a dropdown menu using materialize-css in Angular2. This dropdown menu is subject to expansion as users add more options to the menu, and consequently the items in the menu are stored in a database. In this case, the database is firebase.
I can get the menu to populate with values from the database using the *ngFor
directive, but only when I don't leave in a disabled and selected option tag at the top.
In other words the following code implements the firebase stuff correctly:
<div class="input-field col m3 s12">
<select formControlName="positiveControl3Bound" materialize="material_select" id="posCntrl3">
<option *ngFor="let opt of retrievedDbOpts">{{opt.$value}}</option>
</select>
<label for="posCntrl3">This one from firebase works b/c there's no disabled selected option:</label>
</div>
But, it's not as user-friendly as the <option disabled selected>Choose from the options</option>
line in the code below (which doesn't successfully implement the firebase list):
<div class="input-field col m3 s12">
<select formControlName="useCase" materialize="material_select" id="useCase">
<option disabled selected>Choose from the options</option>
<option *ngFor="let opt of retrievedDbOpts">{{opt.$value}}</option>
</select>
<label for="useCase">But this one from firebase doesn't work:</label>
</div>
I have a reproducible example here:
git clone https://github.com/Atticus29/materializeAngularFormSO.git
cd materializeAngularFormSO
npm install
ng serve
Then, open a browser and navigate to http://localhost:4200/
I executed your code and saw these results:
ERROR Error: Cannot find control with name: 'positiveControl1Bound'
ERROR Error: Cannot find control with name: 'positiveControl2Bound'
ERROR Error: Cannot find control with name: 'positiveControl3Bound'
ERROR Error: Cannot find control with name: 'useCase'
I modified your ngOnInit
to declare the form controls mentioned in the error messages:
ngOnInit() {
this.testForm = this.fb.group({
positiveControl1Bound: '', // Added this line
positiveControl2Bound: '', // Added this line
positiveControl3Bound: '', // Added this line
useCase: '', // Added this line
});
this.db.getOpts().subscribe(opts=>{
this.retrievedDbOpts = opts;
});
}
Executing the application after that change, I see no errors in the console, and the last select element now shows the items from the database in addition to the disabled first option.
Update: there was another problem when your tried to add an empty disabled option as the first item, and fill the options with items from the database. If the disabled option was selected, the other options did not show up; and if the disabled option was not selected, it was not displayed by default.
It appears that getting the options from the database first, and then making the first option disabled, allows to have the first option selected and the other options present in the list. Also, the first option should not be selected before getting the other options, so I had to remove that attribute and give the option a dummy value (e.g. value="(choose)"
). Here is the code for the age class list:
<div class="input-field col m4 s12">
<select formControlName="ageClassBound" materialize="material_select" id="ageClass">
<option value="(choose)" [disabled]="disabledAgeClass" >Choose age class</option>
<option *ngFor="let age of ageClasses">{{age.$value}}</option>
</select>
<label for="ageClass">Age Class</label>
</div>
disabledAgeClass: boolean = false;
this.db.getAgeClasses().takeUntil(this.ngUnsubscribe).subscribe(ageClasses=>{
this.ageClasses = ageClasses;
this.disabledAgeClass = true;
});