显示数据库获取的值(如果存在)否则在 ng-select angular 中显示默认文本
show database fetched values if present else show default text in ng-select angular
我在 angular 中有 3 个国家、州、城市的下拉菜单。我使用 ng-select 模块来处理参考 here 中的那些 dowpdowns。在国家/地区更改状态时填充,在状态更改时城市填充。
模板HTML
<ng-select formControlName="country" (change)="onChangeCountry($event)" >
<ng-option value="dbCountryId ? dbCountryId : ''">{{dbCountryName ? dbCountryName : 'Select Country' }}</ng-option>
<ng-option *ngFor="let country of countryInfo" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<ng-select formControlName="state" (change)="onChangeState($event)">
<ng-option value="dbStateId ? dbStateId : ''">{{dbStateName ? dbStateName : 'Select State' }}</ng-option>
<ng-option *ngFor="let state of stateInfo" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<ng-select formControlName="city" >
<ng-option value="dbCityId ? dbCityId : ''">{{dbCityName ? dbCityName : 'Select City' }}</ng-option>
<ng-option *ngFor="let city of cityInfo" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
ts代码
this.userService.getUserDetails(userDetails.id).subscribe((results) => {
if (results['status'] === true) {
this.dbCountryName = results.data.country ? results.data.country : null;
this.dbCountryId = results.data.country_id
? results.data.country_id
: null;
this.dbStateName = results.data.state ? results.data.state : null;
this.dbStateId = results.data.state_id
? results.data.state_id
: null;
this.dbCityName = results.data.city ? results.data.city : null;
this.dbCityId = results.data.city_id ? results.data.city_id : null;
this.form.patchValue({
country:
results.data.country_id === null ? '' : results.data.country_id,
state:
results.data.state_id === null ? '' : results.data.state_id,
city: results.data.city_id === null ? '' : results.data.city_id,
});
}
});
我使用相同的表单来添加和编辑数据。我正在存储国家、州、城市的 ID。在 api 响应中,我得到了存储的 ID、字段名称。我已经用相应的表单控件修补了 id。
我有两个问题。
- 'Select country/state/city' 和默认文本一样,它显示在下拉列表中而不是输入框中
- 我无法正确显示获取的数据。它显示如下
如何使用 angular 中的 ng-select 解决这些问题?请帮助和指导。谢谢。
编辑
模板代码
<div class="col-sm-6">
<div class="form-group">
<label for="country">Country <b style="color: red">*</b></label><ng-select formControlName="country" (change)="onChangeCountry($event)" [ngClass]="{ 'error_border': submitted && f.country.errors }">
<ng-option *ngFor="let country of countryInfo" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.country.errors" class="text-danger">
<div *ngIf="f.country.errors.required">Country is required</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="state">State <b style="color: red">*</b></label>
<ng-select formControlName="state" [ngClass]="{ 'error_border': submitted && f.state.errors }" (change)="onChangeState($event)">
<ng-option *ngFor="let state of stateInfo" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.state.errors" class="text-danger">
<div *ngIf="f.state.errors.required">State is required</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="city">City <b style="color: red">*</b></label>
<ng-select formControlName="city" [ngClass]="{ 'error_border': submitted && f.city.errors }">
<ng-option *ngFor="let city of cityInfo" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.city.errors" class="text-danger">
<div *ngIf="f.city.errors.required">City is required</div>
</div>
</div>
</div>
ts代码
export class EditProfileComponent implements OnInit {
stateInfo: any[] = [];
countryInfo: any[] = [];
cityInfo: any[] = [];
dbCountryName = '';
dbCountryId = 0;
dbStateName = '';
dbStateId = 0;
dbCityName = '';
dbCityId = 0;
ngOnInit() {
this.form = this.formBuilder.group({
country: ['Select Country', Validators.required],
state: ['Select State', Validators.required],
city: ['Select City', Validators.required],
});
this.userService.getUserDetails(userDetails.id).subscribe((results) => {
if (results['status'] === true) {
this.dbStateName = results.data.state ? results.data.state : null;
this.dbStateId = results.data.state_id
? results.data.state_id
: null;
this.dbCityName = results.data.city ? results.data.city : null;
this.dbCityId = results.data.city_id ? results.data.city_id : null;
this.dbCountryName = results.data.country ? results.data.country : null;
this.dbCountryId = results.data.country_id
? results.data.country_id
: null;
this.cscService.getCountries().subscribe((result) => {
this.countryInfo = result.data;
this.form.patchValue({
country: this.dbCountryId
});
});
this.cscService.getStates(this.dbCountryId).subscribe((result) => {
this.stateInfo = result.data;
this.form.patchValue({
state: this.dbStateId
});
});
this.cscService
.getCities(this.dbStateId)
.subscribe((result) => {
this.cityInfo = result.data;
this.form.patchValue({
city: this.dbCityId
});
}
);
this.form.patchValue({
// country:
// results.data.country_id === null ? 'Select Country' : results.data.country_id,
// state:
// results.data.state_id === null ? 'Select State' : results.data.state_id,
// city: results.data.city_id === null ? 'Select City' : results.data.city_id,
});
}
});
}
getCountries() {
this.cscService.getCountries().subscribe((result) => {
this.countryInfo = result.data;
});
}
onChangeCountry(countryId: number) {
if (countryId) {
this.cscService.getStates(countryId).subscribe((result) => {
this.stateInfo = result.data;
this.cityInfo = null;
});
this.form.patchValue({
state: "Select State",
city: "Select City"
});
} else {
this.stateInfo = null;
this.cityInfo = null;
}
}
onChangeState(stateId: number) {
if (stateId) {
this.cscService
.getCities(stateId)
.subscribe((result) => (this.cityInfo = result.data));
this.form.patchValue({ city: "Select City" });
} else {
this.cityInfo = null;
}
}
}
国家数据响应
状态数据响应 - 进入国家 select(我有 selected 国家 ID =1)
城市数据响应 - 进入状态 select(我有 selected 状态 id =42)
这个解决方案似乎有效。您需要控制器的 ngOnInit 函数中的 formControl 功能。希望这有帮助。
在 html 文件中,我有:
<div class="position">
<form [formGroup]="FormOne">
<ng-select
[formControlName]="city"
(change)="onChangeCity($event)"
placeholder="Select City"
><ng-option *ngFor="let city of cities" [value]="city.id">{{
city.name
}}</ng-option>
</ng-select>
</form>
</div>
在控制器中我有这样的例子:
import { Component, OnInit } from '@angular/core';
import {
FormGroup,
Validators,
FormControl,
AbstractControl,
} from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
cities = [
{ id: 1, name: 'abc' },
{ id: 2, name: 'def' },
{ id: 3, name: 'ghi' },
{ id: 4, name: 'jkl' },
{ id: 5, name: 'mno' },
];
FormOne: FormGroup;
constructor() {}
ngOnInit() {
this.FormOne = new FormGroup({
city: new FormControl(null, Validators.required),
});
}
}
您应该尝试以下选项状态的项目
<ng-container ngFor="let country in countries"> \ you can apply forloop like this and it will show default value
<ng-select
[items]="{{country.name}}"
formControlName="country"
bindLabel="label"
[multiple]="true"
placeholder="Select Country"
[(ngModel)]="selectedAttributes">
</ng-select>
</ng-container>
添加以下模块
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
FormsModule,
NgSelectModule,
有关更多信息,您可以查看此 link ng-select docs
据我了解,您正在使用 Reactive Forms 来管理这些控件。如果这不是真的,请告诉我。
我建议的 HTML 模板与您的类似,但更简单。我建议不要为所选值/默认消息添加单独的 <ng-option>
:
<ng-select formControlName="country" (change)="onChangeCountry($event)" style="width: 200px;">
<ng-option *ngFor="let country of countries" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<ng-select formControlName="state" (change)="onChangeState($event)" style="width: 200px;">
<ng-option *ngFor="let state of statesToShow" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<ng-select formControlName="city" (change)="onChangeCity($event)" style="width: 200px;">
<ng-option *ngFor="let city of citiesToShow" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
我还包含了一个 TS 文件,其中包含有关如何设置的工作示例
- 适当的占位符消息。
- 已选择的值。请参阅
prefefinedValues()
函数。
请注意,为了使 2. 按预期工作,元素的 ID 需要在当前为控件选择的数据源中(在我的示例中 statesToShow
或 citiesToShow
).如果没有,它将显示为文本(可能是您遇到的)。
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'test2';
guestForm: FormGroup;
selectedCar: number = 0;
// this is the data source for the STATES drop-down (initially empty)
// => will be populated when a COUNTRY is selected
public statesToShow: Array<any> = [];
// this is the data source for the CITIES drop-down (initially empty)
// => will be populated when a STATE is selected
public citiesToShow: Array<any> = [];
// TEST data start
public countries = [
{ id: 1, name: 'Romania' },
{ id: 2, name: 'USA' },
{ id: 3, name: 'France' },
{ id: 4, name: 'Spain' },
];
public states = [
[],
[
{id: 1, name: "Cluj"},
{id: 2, name: "Valcea"},
{id: 3, name: "Sibiu"},
{id: 4, name: "Mures"},
],
[
{id: 5, name: "New York"},
{id: 6, name: "Oregon"},
{id: 7, name: "Arizona"},
{id: 8, name: "Texas"},
],
[
{id: 9, name: "Normandie"},
{id: 10, name: "Ile-de-France"},
{id: 11, name: "Grand Est"},
{id: 12, name: "Occitanie"},
],
[
{id: 13, name: "Alicante"},
{id: 14, name: "Valencia"},
{id: 15, name: "Sevilla"},
{id: 16, name: "Malaga"},
]
];
public cities = [
[],
[
{id: 1, name: "Cluj-Napoca"},
{id: 2, name: "Turda"},
{id: 3, name: "Huedin"},
],
[
{id: 4, name: "Ramnicul Valcea"},
{id: 5, name: "Horezu"},
{id: 6, name: "Olanesti"},
],
[],
[],
[
{id: 10, name: "New York city 1"},
{id: 11, name: "New York city 2"},
{id: 12, name: "New York city 3"},
],
[
{id: 13, name: "Oregon city 1"},
{id: 14, name: "Oregon city 2"},
{id: 15, name: "Oregon city 3"},
]
]
// TEST data end
private dbCountryId: number | null = null;
private dbStateId: number | null = null;
private dbCityId: number | null = null;
constructor(private _fb: FormBuilder) {
// add default placeholder messages for all the controls
this.guestForm = this._fb.group({
country: ['Please select country', null],
state: ['Please select state', null],
city: ['Please select city', null]
});
}
ngOnInit() {
}
onChangeCountry(value: number) {
// set the data source for the STATES drop-down
this.statesToShow = this.states[value];
// display placeholders for STATES and CITIES until the user
// selects the values
this.guestForm.patchValue({
state: "Please select state !",
city: "Please select city !"
});
}
onChangeState(value: number) {
// set the data source for the CITIES drop-down
this.citiesToShow = this.cities[value] ? this.cities[value] : [];
// display the placeholder until the user selects a new city
this.guestForm.patchValue({ city: "Please select city !" });
}
onChangeCity(value: number) {
console.log(value);
}
// example on how to correctly set preselected values
// in the controls
predefinedValues() {
// preselected values (MUST BE A VALID COMBINATION)
this.dbCountryId = 2;
this.dbStateId = 6;
this.dbCityId = 14;
// set the sources for STATES and CITIES drop-downs
this.statesToShow = this.states[this.dbCountryId];
this.citiesToShow = this.cities[this.dbStateId];
// set the preselected IDs as current value in all drop-downs
this.guestForm.patchValue({
country: this.dbCountryId,
state: this.dbStateId,
city: this.dbCityId
});
}
}
编辑: 从服务器加载数据
当从服务器接收到数据时,我们需要等待信息到达,然后再对表单控件进行任何修补。 predefinedValues
函数变为:
predefinedValues() {
// read saved database values:
this._dataService.getSavedDatabaseValues()
.then(data => {
this.dbCountryId = data.dbCountryId;
this.dbStateId = data.dbStateId;
this.dbCityId = data.dbCityId;
// now that we have the saved IDs,
// load countries, states & cities for the saved data
this._dataService.getCountries()
.then(data => {
this.countriesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
country: this.dbCountryId
});
});
this._dataService.getStates(this.dbCountryId)
.then(data => {
this.statesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
state: this.dbStateId
});
});
this._dataService.getCities(this.dbStateId)
.then(data => {
this.citiesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
city: this.dbCityId
});
});
})
}
在ngOnInit
中可以直接调用该函数来加载之前保存的数据。此外,当 countries
或 states
选择之一发生变化时,我们需要从服务器加载数据。
onChangeCountry(value: number) {
// set the data source for the STATES drop-down
this._dataService.getStates(value)
.then(data => {
this.statesToShow = data;
});
// display placeholders for STATES and CITIES until the user
// selects the values
this.guestForm.patchValue({
state: "Please select state !",
city: "Please select city !"
});
}
编辑 2: 为了解决 required
验证的问题,我建议使用自定义验证器:
import {AbstractControl, ValidatorFn} from '@angular/forms';
export function selectIsRequired(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
console.log("validator:", control.value);
return control.value === 'Select Country'
|| control.value === 'Select State'
|| control.value === 'Select City'
|| isNaN(parseInt(control.value))
? {required: control.value} : null;
}
}
这将像这样应用于 select
控件:
this.guestForm = this._fb.group({
country: ['Select country', selectIsRequired()],
state: ['Select state', selectIsRequired()],
city: ['Select city', selectIsRequired()]
});
我在 angular 中有 3 个国家、州、城市的下拉菜单。我使用 ng-select 模块来处理参考 here 中的那些 dowpdowns。在国家/地区更改状态时填充,在状态更改时城市填充。
模板HTML
<ng-select formControlName="country" (change)="onChangeCountry($event)" >
<ng-option value="dbCountryId ? dbCountryId : ''">{{dbCountryName ? dbCountryName : 'Select Country' }}</ng-option>
<ng-option *ngFor="let country of countryInfo" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<ng-select formControlName="state" (change)="onChangeState($event)">
<ng-option value="dbStateId ? dbStateId : ''">{{dbStateName ? dbStateName : 'Select State' }}</ng-option>
<ng-option *ngFor="let state of stateInfo" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<ng-select formControlName="city" >
<ng-option value="dbCityId ? dbCityId : ''">{{dbCityName ? dbCityName : 'Select City' }}</ng-option>
<ng-option *ngFor="let city of cityInfo" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
ts代码
this.userService.getUserDetails(userDetails.id).subscribe((results) => {
if (results['status'] === true) {
this.dbCountryName = results.data.country ? results.data.country : null;
this.dbCountryId = results.data.country_id
? results.data.country_id
: null;
this.dbStateName = results.data.state ? results.data.state : null;
this.dbStateId = results.data.state_id
? results.data.state_id
: null;
this.dbCityName = results.data.city ? results.data.city : null;
this.dbCityId = results.data.city_id ? results.data.city_id : null;
this.form.patchValue({
country:
results.data.country_id === null ? '' : results.data.country_id,
state:
results.data.state_id === null ? '' : results.data.state_id,
city: results.data.city_id === null ? '' : results.data.city_id,
});
}
});
我使用相同的表单来添加和编辑数据。我正在存储国家、州、城市的 ID。在 api 响应中,我得到了存储的 ID、字段名称。我已经用相应的表单控件修补了 id。
我有两个问题。
- 'Select country/state/city' 和默认文本一样,它显示在下拉列表中而不是输入框中
- 我无法正确显示获取的数据。它显示如下
如何使用 angular 中的 ng-select 解决这些问题?请帮助和指导。谢谢。
编辑
模板代码
<div class="col-sm-6">
<div class="form-group">
<label for="country">Country <b style="color: red">*</b></label><ng-select formControlName="country" (change)="onChangeCountry($event)" [ngClass]="{ 'error_border': submitted && f.country.errors }">
<ng-option *ngFor="let country of countryInfo" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.country.errors" class="text-danger">
<div *ngIf="f.country.errors.required">Country is required</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="state">State <b style="color: red">*</b></label>
<ng-select formControlName="state" [ngClass]="{ 'error_border': submitted && f.state.errors }" (change)="onChangeState($event)">
<ng-option *ngFor="let state of stateInfo" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.state.errors" class="text-danger">
<div *ngIf="f.state.errors.required">State is required</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="city">City <b style="color: red">*</b></label>
<ng-select formControlName="city" [ngClass]="{ 'error_border': submitted && f.city.errors }">
<ng-option *ngFor="let city of cityInfo" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
<div *ngIf="submitted && f.city.errors" class="text-danger">
<div *ngIf="f.city.errors.required">City is required</div>
</div>
</div>
</div>
ts代码
export class EditProfileComponent implements OnInit {
stateInfo: any[] = [];
countryInfo: any[] = [];
cityInfo: any[] = [];
dbCountryName = '';
dbCountryId = 0;
dbStateName = '';
dbStateId = 0;
dbCityName = '';
dbCityId = 0;
ngOnInit() {
this.form = this.formBuilder.group({
country: ['Select Country', Validators.required],
state: ['Select State', Validators.required],
city: ['Select City', Validators.required],
});
this.userService.getUserDetails(userDetails.id).subscribe((results) => {
if (results['status'] === true) {
this.dbStateName = results.data.state ? results.data.state : null;
this.dbStateId = results.data.state_id
? results.data.state_id
: null;
this.dbCityName = results.data.city ? results.data.city : null;
this.dbCityId = results.data.city_id ? results.data.city_id : null;
this.dbCountryName = results.data.country ? results.data.country : null;
this.dbCountryId = results.data.country_id
? results.data.country_id
: null;
this.cscService.getCountries().subscribe((result) => {
this.countryInfo = result.data;
this.form.patchValue({
country: this.dbCountryId
});
});
this.cscService.getStates(this.dbCountryId).subscribe((result) => {
this.stateInfo = result.data;
this.form.patchValue({
state: this.dbStateId
});
});
this.cscService
.getCities(this.dbStateId)
.subscribe((result) => {
this.cityInfo = result.data;
this.form.patchValue({
city: this.dbCityId
});
}
);
this.form.patchValue({
// country:
// results.data.country_id === null ? 'Select Country' : results.data.country_id,
// state:
// results.data.state_id === null ? 'Select State' : results.data.state_id,
// city: results.data.city_id === null ? 'Select City' : results.data.city_id,
});
}
});
}
getCountries() {
this.cscService.getCountries().subscribe((result) => {
this.countryInfo = result.data;
});
}
onChangeCountry(countryId: number) {
if (countryId) {
this.cscService.getStates(countryId).subscribe((result) => {
this.stateInfo = result.data;
this.cityInfo = null;
});
this.form.patchValue({
state: "Select State",
city: "Select City"
});
} else {
this.stateInfo = null;
this.cityInfo = null;
}
}
onChangeState(stateId: number) {
if (stateId) {
this.cscService
.getCities(stateId)
.subscribe((result) => (this.cityInfo = result.data));
this.form.patchValue({ city: "Select City" });
} else {
this.cityInfo = null;
}
}
}
国家数据响应
状态数据响应 - 进入国家 select(我有 selected 国家 ID =1)
城市数据响应 - 进入状态 select(我有 selected 状态 id =42)
这个解决方案似乎有效。您需要控制器的 ngOnInit 函数中的 formControl 功能。希望这有帮助。
在 html 文件中,我有:
<div class="position">
<form [formGroup]="FormOne">
<ng-select
[formControlName]="city"
(change)="onChangeCity($event)"
placeholder="Select City"
><ng-option *ngFor="let city of cities" [value]="city.id">{{
city.name
}}</ng-option>
</ng-select>
</form>
</div>
在控制器中我有这样的例子:
import { Component, OnInit } from '@angular/core';
import {
FormGroup,
Validators,
FormControl,
AbstractControl,
} from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
cities = [
{ id: 1, name: 'abc' },
{ id: 2, name: 'def' },
{ id: 3, name: 'ghi' },
{ id: 4, name: 'jkl' },
{ id: 5, name: 'mno' },
];
FormOne: FormGroup;
constructor() {}
ngOnInit() {
this.FormOne = new FormGroup({
city: new FormControl(null, Validators.required),
});
}
}
您应该尝试以下选项状态的项目
<ng-container ngFor="let country in countries"> \ you can apply forloop like this and it will show default value
<ng-select
[items]="{{country.name}}"
formControlName="country"
bindLabel="label"
[multiple]="true"
placeholder="Select Country"
[(ngModel)]="selectedAttributes">
</ng-select>
</ng-container>
添加以下模块
import { NgSelectModule } from '@ng-select/ng-select';
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [
FormsModule,
NgSelectModule,
有关更多信息,您可以查看此 link ng-select docs
据我了解,您正在使用 Reactive Forms 来管理这些控件。如果这不是真的,请告诉我。
我建议的 HTML 模板与您的类似,但更简单。我建议不要为所选值/默认消息添加单独的 <ng-option>
:
<ng-select formControlName="country" (change)="onChangeCountry($event)" style="width: 200px;">
<ng-option *ngFor="let country of countries" [value]="country.id">{{country.name}}</ng-option>
</ng-select>
<ng-select formControlName="state" (change)="onChangeState($event)" style="width: 200px;">
<ng-option *ngFor="let state of statesToShow" [value]="state.id">{{state.name}}</ng-option>
</ng-select>
<ng-select formControlName="city" (change)="onChangeCity($event)" style="width: 200px;">
<ng-option *ngFor="let city of citiesToShow" [value]="city.id">{{city.name}}</ng-option>
</ng-select>
我还包含了一个 TS 文件,其中包含有关如何设置的工作示例
- 适当的占位符消息。
- 已选择的值。请参阅
prefefinedValues()
函数。
请注意,为了使 2. 按预期工作,元素的 ID 需要在当前为控件选择的数据源中(在我的示例中 statesToShow
或 citiesToShow
).如果没有,它将显示为文本(可能是您遇到的)。
import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'test2';
guestForm: FormGroup;
selectedCar: number = 0;
// this is the data source for the STATES drop-down (initially empty)
// => will be populated when a COUNTRY is selected
public statesToShow: Array<any> = [];
// this is the data source for the CITIES drop-down (initially empty)
// => will be populated when a STATE is selected
public citiesToShow: Array<any> = [];
// TEST data start
public countries = [
{ id: 1, name: 'Romania' },
{ id: 2, name: 'USA' },
{ id: 3, name: 'France' },
{ id: 4, name: 'Spain' },
];
public states = [
[],
[
{id: 1, name: "Cluj"},
{id: 2, name: "Valcea"},
{id: 3, name: "Sibiu"},
{id: 4, name: "Mures"},
],
[
{id: 5, name: "New York"},
{id: 6, name: "Oregon"},
{id: 7, name: "Arizona"},
{id: 8, name: "Texas"},
],
[
{id: 9, name: "Normandie"},
{id: 10, name: "Ile-de-France"},
{id: 11, name: "Grand Est"},
{id: 12, name: "Occitanie"},
],
[
{id: 13, name: "Alicante"},
{id: 14, name: "Valencia"},
{id: 15, name: "Sevilla"},
{id: 16, name: "Malaga"},
]
];
public cities = [
[],
[
{id: 1, name: "Cluj-Napoca"},
{id: 2, name: "Turda"},
{id: 3, name: "Huedin"},
],
[
{id: 4, name: "Ramnicul Valcea"},
{id: 5, name: "Horezu"},
{id: 6, name: "Olanesti"},
],
[],
[],
[
{id: 10, name: "New York city 1"},
{id: 11, name: "New York city 2"},
{id: 12, name: "New York city 3"},
],
[
{id: 13, name: "Oregon city 1"},
{id: 14, name: "Oregon city 2"},
{id: 15, name: "Oregon city 3"},
]
]
// TEST data end
private dbCountryId: number | null = null;
private dbStateId: number | null = null;
private dbCityId: number | null = null;
constructor(private _fb: FormBuilder) {
// add default placeholder messages for all the controls
this.guestForm = this._fb.group({
country: ['Please select country', null],
state: ['Please select state', null],
city: ['Please select city', null]
});
}
ngOnInit() {
}
onChangeCountry(value: number) {
// set the data source for the STATES drop-down
this.statesToShow = this.states[value];
// display placeholders for STATES and CITIES until the user
// selects the values
this.guestForm.patchValue({
state: "Please select state !",
city: "Please select city !"
});
}
onChangeState(value: number) {
// set the data source for the CITIES drop-down
this.citiesToShow = this.cities[value] ? this.cities[value] : [];
// display the placeholder until the user selects a new city
this.guestForm.patchValue({ city: "Please select city !" });
}
onChangeCity(value: number) {
console.log(value);
}
// example on how to correctly set preselected values
// in the controls
predefinedValues() {
// preselected values (MUST BE A VALID COMBINATION)
this.dbCountryId = 2;
this.dbStateId = 6;
this.dbCityId = 14;
// set the sources for STATES and CITIES drop-downs
this.statesToShow = this.states[this.dbCountryId];
this.citiesToShow = this.cities[this.dbStateId];
// set the preselected IDs as current value in all drop-downs
this.guestForm.patchValue({
country: this.dbCountryId,
state: this.dbStateId,
city: this.dbCityId
});
}
}
编辑: 从服务器加载数据
当从服务器接收到数据时,我们需要等待信息到达,然后再对表单控件进行任何修补。 predefinedValues
函数变为:
predefinedValues() {
// read saved database values:
this._dataService.getSavedDatabaseValues()
.then(data => {
this.dbCountryId = data.dbCountryId;
this.dbStateId = data.dbStateId;
this.dbCityId = data.dbCityId;
// now that we have the saved IDs,
// load countries, states & cities for the saved data
this._dataService.getCountries()
.then(data => {
this.countriesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
country: this.dbCountryId
});
});
this._dataService.getStates(this.dbCountryId)
.then(data => {
this.statesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
state: this.dbStateId
});
});
this._dataService.getCities(this.dbStateId)
.then(data => {
this.citiesToShow = data;
// now that the data binding to the control is complete
// we can do the patching
this.guestForm.patchValue({
city: this.dbCityId
});
});
})
}
在ngOnInit
中可以直接调用该函数来加载之前保存的数据。此外,当 countries
或 states
选择之一发生变化时,我们需要从服务器加载数据。
onChangeCountry(value: number) {
// set the data source for the STATES drop-down
this._dataService.getStates(value)
.then(data => {
this.statesToShow = data;
});
// display placeholders for STATES and CITIES until the user
// selects the values
this.guestForm.patchValue({
state: "Please select state !",
city: "Please select city !"
});
}
编辑 2: 为了解决 required
验证的问题,我建议使用自定义验证器:
import {AbstractControl, ValidatorFn} from '@angular/forms';
export function selectIsRequired(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
console.log("validator:", control.value);
return control.value === 'Select Country'
|| control.value === 'Select State'
|| control.value === 'Select City'
|| isNaN(parseInt(control.value))
? {required: control.value} : null;
}
}
这将像这样应用于 select
控件:
this.guestForm = this._fb.group({
country: ['Select country', selectIsRequired()],
state: ['Select state', selectIsRequired()],
city: ['Select city', selectIsRequired()]
});