Reputation: 11458
I have two <select>
elements, one for the Districts and the other one for the Cities. I get the districts by calling the function getDistricts()
from ngOnInit()
function. So far so good.
I don't know how to tell angular to fetch the new cities to the cities' select element. I tried to do like in the code below, but I've got an error:
ORIGINAL EXCEPTION: TypeError: Cannot read property 'cities' of undefined
It happens of course because the selectedDistrict
is undefined in the start.
This is an example of a district object. (it includes the cities in it).
{
"id": 5,
"name": "A district",
"cities": [
{
"id": 59,
"name": "City 1"
},
{
"id": 60,
"name": "City 2"
}
]
},
district.service.ts:
import {Injectable} from "@angular/core";
import 'rxjs/add/operator/toPromise';
import {District} from "./district";
import {HttpClientService} from "../http-client/http-client.service";
@Injectable()
export class DistrictService {
private districtsUrl = 'districts/all';
constructor(private httpClient: HttpClientService) {
this.httpClient = httpClient;
}
getDistricts(): Promise<District[]> {
return this.httpClient.get(this.districtsUrl)
.toPromise()
.then(response => response.json().data)
.catch(this.handleError);
}
getDistrict(district: string): Promise<District> {
return this.getDistricts()[district];
}
private handleError(error: any) {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
view-search.component.ts:
export class ViewSearchComponent implements OnInit {
districts: district[];
selectedDistrict: district;
constructor(private districtService: districtService) {}
ngOnInit() {
this.getDistricts();
}
getDistricts() {
return this.districtService.getDistricts().then(districts => this.districts = districts);
}
selectDistrict(district: district) {
this.selectedDistrict = district;
}
}
view.search.component.html
<select class="search-select">
<option *ngFor="let district of districts" (click)="selectDistrict(district)">
{{ district.name }}
</option>
</select>
<select class="search-select">
<option *ngFor="let city of selectedDistrict.cities ">
{{ city.name }}
</option>
</select>
Upvotes: 0
Views: 126
Reputation: 10520
Very few people know that Angular2 supports elvis operator (i.e. ?) in templates which is extremely useful for asynchronous data streams. For that, you have to update the template as,
<select class="search-select">
<option *ngFor="let city of selectedDistrict?.cities ">
{{ city.name }}
</option>
</select>
Upvotes: 1
Reputation: 11458
Instead of initializing my selectedDistrict
, I just had to add *ngIf="selectedDistrict" to my select
element.
Upvotes: 0
Reputation: 10603
Try to initialize your selectedDistrict: district;
selectedDistrict: district = {};
also for selecting an option I don't think this is a good idea (click)="selectDistrict(district)"
because you could theoretically use the keyboard/arrows to select an item
so you should use the onchange
event
<select (change)="alert(this.options[this.selectedIndex].text);">
Upvotes: 1
Reputation: 1234
try to initialize the districts: district[]; array you can do that like:
districts = [];
the problem is that you are trying to access city property of an uninitialized object. you need to make sure that you districts objects are initialized.
for example using new
this.selectedDistrict = new District();
or
district = { "id": 5,
"name": "A district",
"cities": [
{
"id": 59,
"name": "City 1"
},
{
"id": 60,
"name": "City 2"
}
]}
also in this code
<select class="search-select">
<option *ngFor="let district of districts" (click)="selectDistrict(district)">
{{ district.name }}
</option>
</select>
make sure that selectDistrict is called correctly
Upvotes: 0