Reputation: 2860
I am having an issue getting select boxes on my Angular2 application to show a default option '--please select--' on page load. I have managed to get this working before but I cannot seem to get this working in this particular instance. I'll show my code then explanations as I show it.
Here is my relevant controller code:
import {Component} from "@angular/core";
import {ProductService} from "../../services/product.service";
import {Subscription} from "rxjs";
import {ActivatedRoute} from "@angular/router";
@Component({
selector : 'product',
moduleId : module.id,
templateUrl : '/app/views/products/product-view.html'
})
export class ProductComponent {
private id:number;
private _subscription: Subscription;
public product;
private price;
private quantity = 0;
constructor(
private _productService: ProductService,
private _activatedRoute: ActivatedRoute
) {
}
getProduct(productId: number) {
this._productService.getProduct(productId)
.subscribe((response) => {
response.success.product.options.forEach((option) => {
this[option.name] = {
name: '-- please select --',
product_option_value_id: 0,
price: 0,
price_prefix: '+'
};
option.product_option_value.unshift({
name: '-- please select --',
product_option_value_id: 0,
price: 0,
price_prefix: '+'
});
});
this.product = response.success.product;
this.generatePrice();
});
}
changeOption(optionValueId, option) {
if(optionValueId != 0) {
let selectedOptionValue = option.product_option_value.filter((option) => {
return option.product_option_value_id == optionValueId;
});
this[option.name] = selectedOptionValue[0];
} else {
this[option.name] = {
name: '-- please select --',
product_option_value_id: 0,
price: 0,
price_prefix: '+'
};
}
this.generatePrice();
}
.....
Here I am getting back information about a product which includes 'options' in a form of an array. This array of objects is iterated over to create the select boxes in the view code which will come later. I add a default '-- please select --' object for each option and put it to the front of the array using unshift. I then also set the controller value for this in the line:
this[option.name] = {
name: '-- please select --',
product_option_value_id: 0,
price: 0,
rice_prefix: '+'
};
The relevant view code is as follows:
<div class='product-options'>
<div class='option' *ngFor='let option of product.options; let i = index'>
<p class='option-name' [innerHTML]='option.name'></p>
<select name='option.name' [ngModel]='option.name' (ngModelChange)='changeOption($event, option)' required>
<option *ngFor='let productOptionValue of option.product_option_value; let j = index;' [value]='productOptionValue.product_option_value_id'>{{ productOptionValue.name }}</option>
</select>
</div>
<div class='price' ngDefaultControl [(ngModel)]="price">{{ price | currency:'GBP':true:'1.2-2' }}</div>
<div class='add-to-basket-wrap'>
<button class='add-to-basket'>add to basket</button>
<button class='increment' (click)="changeQuantity('down')">-</button>
<input type='text' name='quantity-to-add' [(ngModel)]="quantity" (click)='addToBasket()' />
<button class='increment'(click)="changeQuantity('up')">+</button>
</div>
</div>
Here I loop through the options then through the values for these options to generate the select boxes. I set the [ngModel] attribute for the select to the same as the one that was saved in my controller. I was under the impression that Angular2 would detect this binding, spot the value was the same as the controller value and then automatically set that as the 'selected' default option.
Can anyone see why this isn't working?
Thanks
Upvotes: 2
Views: 1115
Reputation: 14087
Looks like your code is not working because your template and your class are not binding to the same properties.
In your component template, when you write this:
<div *ngFor="let option of product.options; let i = index">
<select [ngModel]="option.name">...</select>
</div>
... you're effectively binding each <select>
to a class property named product.options[i].name
.
On the other hand, in your component class, when you write this:
changeOption(optionValueId, option) {
this[option.name] = selectedOptionValue[0];
}
... you're writing to a class property named after whatever string is contained in option.name
, e.g. foo
.
As you can see, product.options[i].name
and foo
don't match. Even by changing foo
to another string, you won't be able to access the property you want.
A few remarks/questions that might help:
this[option.name] = ...
. Why not store them in a dedicated this.options
property that you can declare, type, and log out for debugging purposes: this.options[option.name] = ...
.<select [ngModel]="..." (ngModelChange)="...">
vs the more compact <select [(ngModel)]="...">
?<div class='price'>
vs <div class="price">
? This is not the usual style.Upvotes: 1