Angular 11 Material - 国家、州和城市的级联自动完成输入
Angular 11 Material - Cascading Autocomplete input for country, state and city
我在使用 Angular 11 和 Angular/Material 的自动完成组件时遇到了一些困难。我需要级联搜索国家、城市和州,但我没有成功。
我找了一个例子,但没找到。
这些字段位于 FormArray 中。它是一个有 3 个块的固定数组。这些地址指的是发票、帐单和送货地址。
下面的代码是我可以开始工作的,仅适用于 Pais。我需要级联到城市和州。如果您 select 国家/地区,它会在城市字段中仅列出 selected 国家/地区的城市...
有人能帮我吗?
<mat-form-field class="full-width">
<input type="text" placeholder="Pais..." aria-label="Pais" matInput
formControlName="country" #country [matAutocomplete]="countryAuto" required>
<button mat-button *ngIf="identificationGroup.get('country').value" matSuffix mat-icon-button
aria-label="Clear" (click)="clearFieldControl(identificationGroup.get('country'))">
<mat-icon>close</mat-icon>
</button>
<mat-autocomplete #countryAuto="matAutocomplete" [displayWith]="displayCountryFn">
<mat-option *ngFor="let option of countryList" [value]="option">
{{ option.name }}
</mat-option>
</mat-autocomplete>
<mat-error *ngFor="let validation of validation_msgs.identificationGroup">
<div *ngIf="identificationGroup.get('country').hasError(validation.type)">
{{validation.message}}
</div>
</mat-error>
<mat-error *ngIf="this.identificationGroup.get('country').invalid">
<span [hidden]="!this.identificationGroup.get('country').errors.required">
Campo é obrigatório.
</span>
</mat-error>
</mat-form-field>
this.filteredCountryOptions[i] = formGroup.controls.country.valueChanges
.pipe(
startWith<string | Country>(''),
map(value => typeof value === 'string' ? value : value.name),
map(name => name ? this._filterCountry(name) : this.countryList?.slice())
);
displayCountryFn(country?: Country): string | undefined {
return country ? country.name : undefined;
}
private _filterCountry(name: string): Country[] {
const filterValue = name?.toLowerCase();
return this.countryList?.filter(option => option?.name?.toLowerCase().indexOf(filterValue) === 0);
}
谢谢...
我输入的代码仅指一个字段。在本例中,Country 字段正常工作。
我需要的是让 State 和 City 字段正常工作。
我需要在其他字段自动完成“州”中选择国家列表时,列出与国家相关的列表,而在选择州时,列出与该州相关的城市。
我使用 Select 组件拥有此功能。
<mat-expansion-panel class="mat-elevation-z4" [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon fontSet="fa" fontIcon="fa-map-marker" fxLayoutAlign="start center"></mat-icon>
<span>Endereços</span>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template>Localização</ng-template>
<mat-slide-toggle (change)="checkCopyValuesAddress($event)" [color]="'primary'">Considerar
os
mesmos dados do endereço de faturamento.</mat-slide-toggle>
<mat-tab-group mat-stretch-tabs id="main">
<mat-tab *ngFor="let tab of getFormArray(identificationFormGroup, 'addresses');let i= index"
[label]="i === 0 ? 'Faturamento' : i === 1 ? 'Cobrança' : 'Entrega'" formArrayName="addresses"
#addresses>
<div [formGroupName]="i">
<div class="row">
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Pais...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="country" #country
required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let country of countryList" [value]="country">
{{country.name}} - {{country.initialsCode}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Estado...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="state" #state
required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let state of stateList" [value]="state">
{{state.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Cidade...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="city" #city required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let city of cityList" [value]="city">
{{city.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-9">
<mat-form-field class="full-width">
<input matInput placeholder="Endereço... " formControlName="address" #address
maxlength="100" required>
<button mat-button
*ngIf="(address.value && i == 0) || ((address.value && i > 0) && !copyValueAddress)"
[disabled]="address.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'address', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{address.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-3">
<mat-form-field class="full-width">
<input matInput placeholder="Número..." formControlName="addressNumber" #addressNumber
maxlength="7" required>
<button mat-button
*ngIf="(addressNumber.value && i == 0) || ((addressNumber.value && i > 0) && !copyValueAddress)"
[disabled]="addressNumber.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressNumber', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressNumber.value.length}}/7.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-3">
<mat-form-field class="full-width">
<input #cep matInput placeholder="CEP... " formControlName="addressZipCode" #addressZipCode
minlength="8" mask="00.000-000" required>
<button mat-button
*ngIf="(addressZipCode.value && i == 0) || ((addressZipCode.value && i > 0) && !copyValueAddress)"
[disabled]="addressZipCode.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressZipCode', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressZipCode.value.replace('.', '').replace('-', '').length}}/8.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-6">
<mat-form-field class="full-width">
<input matInput placeholder="Complemento... " formControlName="addressComplement"
#addressComplement maxlength="100">
<button mat-button
*ngIf="(addressComplement.value && i == 0) || ((addressComplement.value && i > 0) && !copyValueAddress)"
[disabled]="addressComplement.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressComplement', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressComplement.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-3">
<mat-form-field class="full-width">
<input matInput placeholder="Bairro..." formControlName="addressNeighborhood"
#addressNeighborhood maxlength="25" required>
<button mat-button
*ngIf="(addressNeighborhood.value && i == 0) || ((addressNeighborhood.value && i > 0) && !copyValueAddress)"
[disabled]="addressNeighborhood.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressNeighborhood', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressNeighborhood.value.length}}/25.
</mat-hint>
</mat-form-field>
</div>
<hr>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="Contato... " formControlName="contactName" #contactName
maxlength="100" required>
<button mat-button
*ngIf="(contactName.value && i == 0) || ((contactName.value && i > 0) && !copyValueAddress)"
[disabled]="contactName.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactName', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactName.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="E-Mail... " formControlName="contactEmail" #contactEmail
maxlength="100" required>
<button mat-button
*ngIf="(contactEmail.value && i == 0) || ((contactEmail.value && i > 0) && !copyValueAddress)"
[disabled]="contactEmail.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactEmail', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactEmail.value.length}}/100.
</mat-hint>
<!-- input field error -->
<mat-error
*ngIf="identificationFormGroup.get('addresses')['controls'][i].value?.contactEmail?.invalid">
<span
[hidden]="!identificationFormGroup.get('addresses')['controls'][i].value?.contactEmail?.errors?.email">
Formato inválido para o campo.
</span>
</mat-error>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="Telefone... " formControlName="contactPhone" #contactPhone
maxlength="100" [mask]="phoneMask" required>
<button mat-button
*ngIf="(contactPhone.value && i == 0) || ((contactPhone.value && i > 0) && !copyValueAddress)"
[disabled]="contactPhone.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactPhone', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactPhone.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-12">
<mat-form-field class="full-width">
<textarea matInput placeholder="Observação..." rows="6" formControlName="observation"
#observation maxlength="500"></textarea>
<button mat-button
*ngIf="(observation.value && i == 0) || ((observation.value && i > 0) && !copyValueAddress)"
[disabled]="observation.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'observation', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{observation.value.length}}/500.
</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
</mat-tab-group>
</mat-expansion-panel>
这是我当前使用的 valueChange 所在的函数。
createAddress(i: number, data: CustomerAddressData = {
id: null,
companyId: null,
addressType: null,
city: null,
state: null,
country: null,
address: null,
addressNeighborhood: null,
addressZipCode: null,
addressNumber: null,
addressComplement: null,
contactName: null,
contactEmail: null,
contactPhone: null,
observation: null
}): FormGroup {
const formGroup = this.formBuilder.group({
id: [data.id === null ? 0 : data.id],
companyId: [data.companyId === null ? 0 : data.companyId],
addressType: [data.addressType === null ? i : 0],
city: [data.city, [Validators.required]],
state: [data.state, [Validators.required]],
country: [data.country, [Validators.required]],
address: [data.address, [Validators.required, Validators.maxLength(100)]],
addressNeighborhood: [data.addressNeighborhood, [Validators.required, Validators.maxLength(25)]],
addressZipCode: [data.addressZipCode, [Validators.required, Validators.minLength(8), Validators.minLength(8)]],
addressNumber: [data.addressNumber, [Validators.required, Validators.maxLength(7)]],
addressComplement: [data.addressComplement, [Validators.maxLength(100)]],
contactName: [data.contactName, [Validators.required, Validators.maxLength(100)]],
contactEmail: [data.contactEmail, [Validators.required, Validators.maxLength(100), Validators.email]],
contactPhone: [data.contactPhone, [Validators.required, Validators.maxLength(100)]],
observation: [data.observation, [Validators.maxLength(500)]],
});
formGroup.controls.addressZipCode.valueChanges
.pipe(
map(x => x !== undefined ? x : x !== null ? x : 0),
map(x => x !== null ? x : 0)
).subscribe();
formGroup.controls.addressZipCode.statusChanges
.pipe(
distinctUntilChanged(),
switchMap(status => status === 'VALID' ?
this.findZipCodeService.findZipCode(formGroup.controls.addressZipCode.value)
: empty()
),
catchError(err => throwError(err))
).subscribe(resp => {
if ('erro' in resp) {
this.toastAlertService.showError(
`CEP ${formGroup.controls.addressZipCode.value} informado não encontrado!`, 'Consulta de CEP.'
);
}
else {
this.auxiliaryDataService.getStates()
.subscribe(stateResult => {
if (resp['localidade'] !== undefined) {
const state = stateResult['data']?.filter(f => f.initialsCode === resp['uf']).map(m => m);
this.auxiliaryDataService.getCityByFilter(state ? state[0].id : 0, null, null, null, true)
.subscribe(s => {
const city = s['data']?.filter(f => f.ibgeCode.toString() === resp['ibge'].toString()).map(m => m);
const country = this.countryList.filter(f => f.initialsCode === 'BR').map(m => m);
formGroup.patchValue({
state: state[0],
city: city[0],
country: country[0],
address: resp['logradouro'],
addressNeighborhood: resp['bairro']
});
});
}
});
}
});
formGroup.controls.state.valueChanges
.pipe(
switchMap((value: number) => {
this.auxiliaryDataService.getCityByFilter(value ? value['id'] : 0, null, null, null, true)
.subscribe(s => {
this.cityList = s['data'];
}, (error) => {
console.log(error);
observableOf(null);
});
return of('');
}),
).subscribe();
formGroup.controls.country.valueChanges
.subscribe(value => {
this.phoneMask = '(00) 0000-0000 || (00) 00000-0000';
if ((value ? value['initialsCode'] : 'BR') !== 'BR') {
this.phoneMask = '';
}
this.auxiliaryDataService.getStateByFilter(value ? value['id'] : 0, null, null, null, true)
.subscribe(s => {
this.stateList = s['data'];
}, (error) => {
console.log(error);
observableOf(null);
});
return of('');
});
formGroup.controls.id.setValue(data.id === null ? 0 : data.id);
formGroup.controls.companyId.setValue(data.companyId === null ? 0 : data.companyId);
formGroup.controls.addressType.setValue(data.addressType === null ? i : 0);
formGroup.controls.city.setValue(data.city);
formGroup.controls.state.setValue(data.state);
formGroup.controls.country.setValue(data.country);
formGroup.controls.address.setValue(data.address);
formGroup.controls.addressNeighborhood.setValue(data.addressNeighborhood);
formGroup.controls.addressZipCode.setValue(data.addressZipCode);
formGroup.controls.addressNumber.setValue(data.addressNumber);
formGroup.controls.addressComplement.setValue(data.addressComplement);
formGroup.controls.contactName.setValue(data.contactName);
formGroup.controls.contactEmail.setValue(data.contactEmail);
formGroup.controls.contactPhone.setValue(data.contactPhone);
formGroup.controls.observation.setValue(data.observation);
return formGroup;
}
我需要将 Select 组件更改为自动完成。我无法在 3 个自动完成组件之间级联。
我在使用 Angular 11 和 Angular/Material 的自动完成组件时遇到了一些困难。我需要级联搜索国家、城市和州,但我没有成功。
我找了一个例子,但没找到。
这些字段位于 FormArray 中。它是一个有 3 个块的固定数组。这些地址指的是发票、帐单和送货地址。
下面的代码是我可以开始工作的,仅适用于 Pais。我需要级联到城市和州。如果您 select 国家/地区,它会在城市字段中仅列出 selected 国家/地区的城市...
有人能帮我吗?
<mat-form-field class="full-width">
<input type="text" placeholder="Pais..." aria-label="Pais" matInput
formControlName="country" #country [matAutocomplete]="countryAuto" required>
<button mat-button *ngIf="identificationGroup.get('country').value" matSuffix mat-icon-button
aria-label="Clear" (click)="clearFieldControl(identificationGroup.get('country'))">
<mat-icon>close</mat-icon>
</button>
<mat-autocomplete #countryAuto="matAutocomplete" [displayWith]="displayCountryFn">
<mat-option *ngFor="let option of countryList" [value]="option">
{{ option.name }}
</mat-option>
</mat-autocomplete>
<mat-error *ngFor="let validation of validation_msgs.identificationGroup">
<div *ngIf="identificationGroup.get('country').hasError(validation.type)">
{{validation.message}}
</div>
</mat-error>
<mat-error *ngIf="this.identificationGroup.get('country').invalid">
<span [hidden]="!this.identificationGroup.get('country').errors.required">
Campo é obrigatório.
</span>
</mat-error>
</mat-form-field>
this.filteredCountryOptions[i] = formGroup.controls.country.valueChanges
.pipe(
startWith<string | Country>(''),
map(value => typeof value === 'string' ? value : value.name),
map(name => name ? this._filterCountry(name) : this.countryList?.slice())
);
displayCountryFn(country?: Country): string | undefined {
return country ? country.name : undefined;
}
private _filterCountry(name: string): Country[] {
const filterValue = name?.toLowerCase();
return this.countryList?.filter(option => option?.name?.toLowerCase().indexOf(filterValue) === 0);
}
谢谢...
我输入的代码仅指一个字段。在本例中,Country 字段正常工作。
我需要的是让 State 和 City 字段正常工作。
我需要在其他字段自动完成“州”中选择国家列表时,列出与国家相关的列表,而在选择州时,列出与该州相关的城市。
我使用 Select 组件拥有此功能。
<mat-expansion-panel class="mat-elevation-z4" [expanded]="true">
<mat-expansion-panel-header>
<mat-panel-title>
<mat-icon fontSet="fa" fontIcon="fa-map-marker" fxLayoutAlign="start center"></mat-icon>
<span>Endereços</span>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template>Localização</ng-template>
<mat-slide-toggle (change)="checkCopyValuesAddress($event)" [color]="'primary'">Considerar
os
mesmos dados do endereço de faturamento.</mat-slide-toggle>
<mat-tab-group mat-stretch-tabs id="main">
<mat-tab *ngFor="let tab of getFormArray(identificationFormGroup, 'addresses');let i= index"
[label]="i === 0 ? 'Faturamento' : i === 1 ? 'Cobrança' : 'Entrega'" formArrayName="addresses"
#addresses>
<div [formGroupName]="i">
<div class="row">
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Pais...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="country" #country
required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let country of countryList" [value]="country">
{{country.name}} - {{country.initialsCode}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Estado...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="state" #state
required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let state of stateList" [value]="state">
{{state.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-sm-4">
<mat-form-field class="full-width">
<mat-label>Cidade...</mat-label>
<mat-select [compareWith]="objectComparisonFunction" formControlName="city" #city required>
<mat-option>-- Selecione --</mat-option>
<mat-option *ngFor="let city of cityList" [value]="city">
{{city.name}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="col-md-9">
<mat-form-field class="full-width">
<input matInput placeholder="Endereço... " formControlName="address" #address
maxlength="100" required>
<button mat-button
*ngIf="(address.value && i == 0) || ((address.value && i > 0) && !copyValueAddress)"
[disabled]="address.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'address', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{address.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-3">
<mat-form-field class="full-width">
<input matInput placeholder="Número..." formControlName="addressNumber" #addressNumber
maxlength="7" required>
<button mat-button
*ngIf="(addressNumber.value && i == 0) || ((addressNumber.value && i > 0) && !copyValueAddress)"
[disabled]="addressNumber.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressNumber', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressNumber.value.length}}/7.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-3">
<mat-form-field class="full-width">
<input #cep matInput placeholder="CEP... " formControlName="addressZipCode" #addressZipCode
minlength="8" mask="00.000-000" required>
<button mat-button
*ngIf="(addressZipCode.value && i == 0) || ((addressZipCode.value && i > 0) && !copyValueAddress)"
[disabled]="addressZipCode.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressZipCode', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressZipCode.value.replace('.', '').replace('-', '').length}}/8.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-6">
<mat-form-field class="full-width">
<input matInput placeholder="Complemento... " formControlName="addressComplement"
#addressComplement maxlength="100">
<button mat-button
*ngIf="(addressComplement.value && i == 0) || ((addressComplement.value && i > 0) && !copyValueAddress)"
[disabled]="addressComplement.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressComplement', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressComplement.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-sm-3">
<mat-form-field class="full-width">
<input matInput placeholder="Bairro..." formControlName="addressNeighborhood"
#addressNeighborhood maxlength="25" required>
<button mat-button
*ngIf="(addressNeighborhood.value && i == 0) || ((addressNeighborhood.value && i > 0) && !copyValueAddress)"
[disabled]="addressNeighborhood.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'addressNeighborhood', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{this.addressNeighborhood.value.length}}/25.
</mat-hint>
</mat-form-field>
</div>
<hr>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="Contato... " formControlName="contactName" #contactName
maxlength="100" required>
<button mat-button
*ngIf="(contactName.value && i == 0) || ((contactName.value && i > 0) && !copyValueAddress)"
[disabled]="contactName.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactName', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactName.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="E-Mail... " formControlName="contactEmail" #contactEmail
maxlength="100" required>
<button mat-button
*ngIf="(contactEmail.value && i == 0) || ((contactEmail.value && i > 0) && !copyValueAddress)"
[disabled]="contactEmail.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactEmail', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactEmail.value.length}}/100.
</mat-hint>
<!-- input field error -->
<mat-error
*ngIf="identificationFormGroup.get('addresses')['controls'][i].value?.contactEmail?.invalid">
<span
[hidden]="!identificationFormGroup.get('addresses')['controls'][i].value?.contactEmail?.errors?.email">
Formato inválido para o campo.
</span>
</mat-error>
</mat-form-field>
</div>
<div class="col-md-4">
<mat-form-field class="full-width">
<input matInput placeholder="Telefone... " formControlName="contactPhone" #contactPhone
maxlength="100" [mask]="phoneMask" required>
<button mat-button
*ngIf="(contactPhone.value && i == 0) || ((contactPhone.value && i > 0) && !copyValueAddress)"
[disabled]="contactPhone.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'contactPhone', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{contactPhone.value.length}}/100.
</mat-hint>
</mat-form-field>
</div>
<div class="col-md-12">
<mat-form-field class="full-width">
<textarea matInput placeholder="Observação..." rows="6" formControlName="observation"
#observation maxlength="500"></textarea>
<button mat-button
*ngIf="(observation.value && i == 0) || ((observation.value && i > 0) && !copyValueAddress)"
[disabled]="observation.disabled" matSuffix mat-icon-button aria-label="Clear"
(click)="clearFieldArrayControl(identificationFormGroup, 'addresses', 'observation', i)">
<mat-icon>close</mat-icon>
</button>
<mat-hint align="end">
{{observation.value.length}}/500.
</mat-hint>
</mat-form-field>
</div>
</div>
</div>
</mat-tab>
</mat-tab-group>
</mat-expansion-panel>
这是我当前使用的 valueChange 所在的函数。
createAddress(i: number, data: CustomerAddressData = {
id: null,
companyId: null,
addressType: null,
city: null,
state: null,
country: null,
address: null,
addressNeighborhood: null,
addressZipCode: null,
addressNumber: null,
addressComplement: null,
contactName: null,
contactEmail: null,
contactPhone: null,
observation: null
}): FormGroup {
const formGroup = this.formBuilder.group({
id: [data.id === null ? 0 : data.id],
companyId: [data.companyId === null ? 0 : data.companyId],
addressType: [data.addressType === null ? i : 0],
city: [data.city, [Validators.required]],
state: [data.state, [Validators.required]],
country: [data.country, [Validators.required]],
address: [data.address, [Validators.required, Validators.maxLength(100)]],
addressNeighborhood: [data.addressNeighborhood, [Validators.required, Validators.maxLength(25)]],
addressZipCode: [data.addressZipCode, [Validators.required, Validators.minLength(8), Validators.minLength(8)]],
addressNumber: [data.addressNumber, [Validators.required, Validators.maxLength(7)]],
addressComplement: [data.addressComplement, [Validators.maxLength(100)]],
contactName: [data.contactName, [Validators.required, Validators.maxLength(100)]],
contactEmail: [data.contactEmail, [Validators.required, Validators.maxLength(100), Validators.email]],
contactPhone: [data.contactPhone, [Validators.required, Validators.maxLength(100)]],
observation: [data.observation, [Validators.maxLength(500)]],
});
formGroup.controls.addressZipCode.valueChanges
.pipe(
map(x => x !== undefined ? x : x !== null ? x : 0),
map(x => x !== null ? x : 0)
).subscribe();
formGroup.controls.addressZipCode.statusChanges
.pipe(
distinctUntilChanged(),
switchMap(status => status === 'VALID' ?
this.findZipCodeService.findZipCode(formGroup.controls.addressZipCode.value)
: empty()
),
catchError(err => throwError(err))
).subscribe(resp => {
if ('erro' in resp) {
this.toastAlertService.showError(
`CEP ${formGroup.controls.addressZipCode.value} informado não encontrado!`, 'Consulta de CEP.'
);
}
else {
this.auxiliaryDataService.getStates()
.subscribe(stateResult => {
if (resp['localidade'] !== undefined) {
const state = stateResult['data']?.filter(f => f.initialsCode === resp['uf']).map(m => m);
this.auxiliaryDataService.getCityByFilter(state ? state[0].id : 0, null, null, null, true)
.subscribe(s => {
const city = s['data']?.filter(f => f.ibgeCode.toString() === resp['ibge'].toString()).map(m => m);
const country = this.countryList.filter(f => f.initialsCode === 'BR').map(m => m);
formGroup.patchValue({
state: state[0],
city: city[0],
country: country[0],
address: resp['logradouro'],
addressNeighborhood: resp['bairro']
});
});
}
});
}
});
formGroup.controls.state.valueChanges
.pipe(
switchMap((value: number) => {
this.auxiliaryDataService.getCityByFilter(value ? value['id'] : 0, null, null, null, true)
.subscribe(s => {
this.cityList = s['data'];
}, (error) => {
console.log(error);
observableOf(null);
});
return of('');
}),
).subscribe();
formGroup.controls.country.valueChanges
.subscribe(value => {
this.phoneMask = '(00) 0000-0000 || (00) 00000-0000';
if ((value ? value['initialsCode'] : 'BR') !== 'BR') {
this.phoneMask = '';
}
this.auxiliaryDataService.getStateByFilter(value ? value['id'] : 0, null, null, null, true)
.subscribe(s => {
this.stateList = s['data'];
}, (error) => {
console.log(error);
observableOf(null);
});
return of('');
});
formGroup.controls.id.setValue(data.id === null ? 0 : data.id);
formGroup.controls.companyId.setValue(data.companyId === null ? 0 : data.companyId);
formGroup.controls.addressType.setValue(data.addressType === null ? i : 0);
formGroup.controls.city.setValue(data.city);
formGroup.controls.state.setValue(data.state);
formGroup.controls.country.setValue(data.country);
formGroup.controls.address.setValue(data.address);
formGroup.controls.addressNeighborhood.setValue(data.addressNeighborhood);
formGroup.controls.addressZipCode.setValue(data.addressZipCode);
formGroup.controls.addressNumber.setValue(data.addressNumber);
formGroup.controls.addressComplement.setValue(data.addressComplement);
formGroup.controls.contactName.setValue(data.contactName);
formGroup.controls.contactEmail.setValue(data.contactEmail);
formGroup.controls.contactPhone.setValue(data.contactPhone);
formGroup.controls.observation.setValue(data.observation);
return formGroup;
}
我需要将 Select 组件更改为自动完成。我无法在 3 个自动完成组件之间级联。