项目中没有维护这个对应关系的API,所以我google到了Google map的API,只需要发get请求发送邮编即可。api地址是
http://maps.googleapis.com/maps/api/geocode/json?address=xxx,这里的address就是接受的邮编。
所以现在需求是:用户输入邮政编码后请求该API得到对应的州和city,然后渲染到对应的字段中。
create-client.component.html

<!-- client form -->
<div animated fadeIn><form class="client-form" class="form-horizontal" [formGroup]="orgForm"><div class="row"><div class="col-md-10"><div class="card"><div class="card-header"><strong>Account Information</strong></div><div class="card-body"><div class="row"><label for="country"class="col-md-3 form-control-label required-label"><span class="asterisk">*</span>Country:</label><div class="col-md-9"><select style="height: 34px;" class="col-md-5 form-control" id="country" name="country" formControlName="country"><option *ngFor="let country of countries"[value]="country">{{ country }}</option></select></div></div><div class="row"><label for="postal"class="col-md-3 form-control-label required-label"><span class="asterisk">*</span>Postal Code:</label><div class="col-md-9"><input id="postal" name="postal"class="col-md-5 form-control"formControlName="postal"placeholder="Enter Client Postal Code" (change)="onPostalChange($event)" ><span class="col-md-5 login-error-alert" *ngIf="this.isFormInputInvalid('postal') &&this.orgForm.get('postal').hasError('required')">Postal Code is required</span><span class="col-md-5 login-error-alert" *ngIf="this.isFormInputInvalid('postal') &&!this.orgForm.get('postal').hasError('required') &&this.orgForm.get('postal').hasError('pattern')">Postal Code must be a 5 digit number</span><span class="col-md-5 login-error-alert" *ngIf="this.isPostalCodeInvalid &&!this.orgForm.get('postal').hasError('pattern') &&!this.orgForm.get('postal').hasError('required')">Postal Code is not available</span></div></div><div class="row"><label for="city"class="col-md-3 form-control-label required-label"><span class="asterisk">*</span>City:</label><div class="col-md-9"><input id="city" name="city" [(ngModel)]="cityName"class="col-md-5 form-control"formControlName="city"placeholder="Enter Client City"><span class="col-md-5 login-error-alert" *ngIf="this.isFormInputInvalid('city') &&this.orgForm.get('city').hasError('required')">City is required</span><span class="col-md-5 login-error-alert" *ngIf="this.isFormInputInvalid('city') &&this.orgForm.get('city').hasError('pattern')">City cannot exceed 40 characters</span></div></div><div class="row"><label for="state"class="col-md-3 form-control-label required-label"><span class="asterisk">*</span>State:</label><div class="col-md-9"><select style="height: 34px;" class="col-md-5 form-control" id="state" formControlName="state"[(ngModel)]="stateAbbreviation" (ngModelChange)="onStateChange($event)"><option *ngFor="let state of stateItems"[value]="state">{{ state }}</option></select><div *ngIf="orgForm.get('state').touched || orgForm.get('state').dirty"><span class="col-md-5 login-error-alert" *ngIf="this.isFormInputInvalid('state') &&this.orgForm.get('state').hasError('required')">State is required</span><span class="col-md-5 login-error-alert" *ngIf="this.isStateValueMismatchWithPostalCode"> Postal Code and State Mismatch</span></div></div></div></div></div><div class="modal-footer col-md-10"><div class="col-md-9"><div class="col-md-5"><button type="button" class="btn btn-dark-rs6 col-md-5" id="reset-button-modal"(click)="orgForm.reset()" style="margin-left: -24px">Reset</button><button type="submit" class="btn btn-green-rs6 col-md-5" id="submit-button-modal"[disabled]="!orgForm.valid || this.isStateValueMismatchWithPostalCode || isPostalCodeInvalid" (click)="onSubmit()"style="float: right; margin-right: -15px">Create</button></div></div></div></form>
</div>

子类:create-client.component.ts

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Location } from '@angular/common';
import { Account } from '../../model/account.model';
import { PaymentTermList } from '../../model/payment-term-list.model';
import { PricingPackage } from '../../model/pricing-package.model';
import { Processor } from '../../model/processor.model';
import { RequestBilling } from '../../model/request-billing.model';
import { User } from '../../model/user.model';
import { DialogService } from '../../service/dialog.service';
import { OrganizationService } from '../../service/organization.service';
import { CreateOrganizationComponent } from '../create-organization/create-organization.component';
import {Regex} from '../../model/regex.model';
import { OrganizationType } from '../../model/organization-type.model';
import {UtilService} from '../../service/util.service';
import {Constants} from '../../utility/constants';
import {Utility} from '../../utility/utility';@Component({selector: 'app-create-client',templateUrl: 'create-client.component.html'
})export class CreateClientComponent extends CreateOrganizationComponent {account: Account = {soldBy: '', ownedBy: '', address: {address1: '', address2: '', city: '', state: '', country: '', postal: ''}, emailAddress: '', locale: {language: {cultureName: ''}},processorList: [{name: ''}]};countries: string[] = [];stateItems: string[] = [];constructor(private fb: FormBuilder, route: ActivatedRoute, dialogService: DialogService,organizationService: OrganizationService, utilService: UtilService,router: Router, location: Location, regex: Regex) {super(route, dialogService, organizationService, router, location, regex, utilService);this.createForm();this.title = 'Client Creation';this.route.queryParams.subscribe((params: Params) => {this.clientId = params['clientId'];this.parentOrganizationId = params['parentOrganizationId'];});this.initProcessorList();this.organizationService.getPaymentTerms().subscribe((paymentTermList: PaymentTermList) => this.paymentTermList = paymentTermList);this.utilService.getCountries().subscribe((countries: string[] ) => this.countries = countries);this.utilService.getStates().subscribe((states: string[] ) => this.stateItems = states);}onSubmit() {this.updateModel();super.onSubmit(OrganizationType.Client);}updateModel() {this.model.account.address.city = this.orgForm.get('city').value;this.model.account.address.state = this.orgForm.get('state').value;this.model.account.address.postal = this.orgForm.get('postal').value;this.model.account.address.country = Utility.convertSpecificCountryNameInShort(this.orgForm.get('country').value);this.model.account.processorList = [];for (const processor of this.processors) {if (processor['checked']) {const p: Processor = {name: processor['name']};this.model.account.processorList.push(p);}}}onPostalChange($event) {this.onPostalChanges(this.orgForm.get('postal').value);}private createForm() {this.orgForm = this.fb.group({state: ['', [Validators.required, Validators.pattern(this.regex.state)]],city: ['', [Validators.required, Validators.pattern(this.regex.city)]],country: ['', [Validators.required]],postal: ['', [Validators.required, Validators.pattern(this.regex.postalCode)]],);}
}

父类:create-organization.component.ts

import { HttpErrorResponse, HttpResponse, HttpResponseBase } from '@angular/common/http';
import { Component, ViewChild, ElementRef } from '@angular/core';
import { AbstractControl, FormGroup } from '@angular/forms';
import { ValidationErrors } from '@angular/forms/src/directives/validators';
import { ActivatedRoute, Params, Router} from '@angular/router';
import { Location } from '@angular/common';
import { Observable } from 'rxjs/Observable';
import { Organization } from '../../model/organization.model';
import { Regex } from '../../model/regex.model';
import { DialogService } from '../../service/dialog.service';
import { OrganizationService } from '../../service/organization.service';
import { Utility } from '../../utility/utility';
import { OrganizationType } from '../../model/organization-type.model';
import { UtilService } from '../../service/util.service';@Component({selector: 'app-create-organization',templateUrl: 'create-organization.component.html'
})
export class CreateOrganizationComponent {parentOrganizationUserName = '';parentOrganizationId: number;orgForm: FormGroup;stateAbbreviationFirstValue = '';isFirstTimeToChoose = true;stateAbbreviation = '';isPostalCodeInvalid = false;isStateValueMismatchWithPostalCode = false;cityName = '';constructor(public route: ActivatedRoute, public dialogService: DialogService, public organizationService: OrganizationService,private router: Router, public location: Location, public regex: Regex, public utilService: UtilService) {}onSubmit(orgType: any) {let parentOrgId = '';if (this.parentOrganizationId) {parentOrgId = this.parentOrganizationId.toString();}this.organizationService.createChildOrganization(this.parentOrganizationUserName, parentOrgId, this.model).subscribe((response: HttpResponseBase) => {if (response instanceof HttpResponse) {this.createdOrgId = response.body['organizationId'];this.resResult = !response.body['customMessage'];this.openDialog(this.resResult, orgType, response.body['customMessage']);} else if (response instanceof HttpErrorResponse) {this.resErrorResult = response.error['text'];this.openDialog(false, orgType, this.resErrorResult);}}, (error) => {this.openDialog(false, orgType, '');});}isFormInputInvalid(input: string): boolean {return Utility.isFormInputInvalid(input, this.orgForm);}isUserNameAvailable(control: AbstractControl): Observable<ValidationErrors | null> {return this.organizationService.getUserNameAvailability(control.value).map((res: any) => res.isUserNameAvailable ? null : res);}/*** Get the state abbreviation with the postal code from google API and judged whether is postal code is valid or not.* @param postalCode postal code.*/onPostalChanges(postalCode: string) {this.isFirstTimeToChoose = true;if (postalCode) {this.utilService.getAddressInfoWithPostalCode(postalCode).subscribe(res => {const address = Utility.filterStateWithPostalCodeFromGoogleApi(res);if (address && address.state) {this.isPostalCodeInvalid = false;this.stateAbbreviation = address.state;this.cityName = address.city;this.isStateValueMismatchWithPostalCode = false;} else {this.isPostalCodeInvalid = true;}});}}/*** When changed the state select value then will call this method,it used to confirm whether* the state value is match with the postal code or not.* @param stateAbbreviationFirstValue the abbreviation of the firstly selected state value.* @param stateAbbreviationNewValue the abbreviation of the now selected state value.*/isStateAndPostalCodeValid(stateAbbreviationNewValue: string, stateAbbreviationFirstValue: string) {if (stateAbbreviationNewValue !== undefined && stateAbbreviationFirstValue !== undefined) {if (stateAbbreviationFirstValue.match(stateAbbreviationNewValue)) {this.isStateValueMismatchWithPostalCode = false;} else {this.isStateValueMismatchWithPostalCode = true;}}}/*** change event on state field* save the first value of state field,and judge whether the postal code and state is match or not.*/onStateChange($event) {if (this.isFirstTimeToChoose === true) {this.stateAbbreviationFirstValue = this.stateAbbreviation;this.isFirstTimeToChoose = false;}this.isStateAndPostalCodeValid(this.stateAbbreviation, this.stateAbbreviationFirstValue);}
}

Utility.ts,解析谷歌api返回的json

/*** Filter the results of requesting google api, retain the state's abbreviation and the city name.* @param res the results from calling the google API.* @returns Address including the abbreviation of State and the city name.*/static filterStateWithPostalCodeFromGoogleApi(res: any): Address {const address: Address = {};if (res['results'].length === 0) {return res[0];} else {const stateNames = res['results'][0]['address_components'].filter(resp => resp['types'][0] === 'administrative_area_level_1').map(re => re['short_name']);const cityNames = res['results'][0]['address_components'].filter(resp => resp['types'][0] === 'locality').map(re => re['long_name']);address.state = stateNames[0];address.city = cityNames[0];return address;}}

测试点击事件ngModelChange

it('should go from model to change event', async(() => {const fixture = TestBed.createComponent(CreateMerchantComponent);const comp = fixture.componentInstance;spyOn(comp, 'onStateChange');comp.stateItems = states;comp.stateAbbreviation = states[1];fixture.detectChanges();const select = fixture.debugElement.query(By.css('#state'));fixture.whenStable().then(() => {select.nativeElement.dispatchEvent(new Event('change'));fixture.detectChanges();expect(comp.onStateChange).toHaveBeenCalledWith('AK');});}));

如何根据美国的邮编带出对应的州呢相关推荐

  1. 带出7个“师弟”,支付宝BASIC College的辅导员是个伪90后

    "我的花名是改之,不是'有则改之无则加勉'的改之,而是'杨过,字改之'的那个改之."一见面,他对自己花名的介绍,就让人耳目一新.至于为什么要用杨过的字给自己起名,他也毫不扭捏地坦诚 ...

  2. SM30里如何输入物料号自动带出物料描述

    新建Table,根据输入的物料号,自动带出描述: SE80根据表生成器里面的函数组进去进行增强: 双击进行维护取数代码即可:

  3. 【GVA】gorm多对多关联使用Preload带出关联表中的数据

    db.Limit(limit).Offset(offset).Preload("BusinessSystemList").Find(&projectManagements) ...

  4. 返回多个不同类型参数的值(out)可变参数一维数组( params )把值从方法中带出(ref) 方法递归(方法自己调用自己与循坏类似注意return每次只能跳出一个方法))...

    //out参数  如果需要在方法中,返回多个值,并且是不同类型,可以使用out参数帮助我们返回.  out参数就是帮助我们在方法中返回多个不同类型的值.  out参数必须在方法的内部为其赋值,而在方法 ...

  5. php 输入汉字自动带出拼音和英文

    需求就是添加一个字段的时候,自动带出中文和英文,方便数据索引. 这里只贴下代码,英文用在线api,中文用类库.我觉得这个拼音类库比较好,不会出现重庆是zhongqing之类的问题,因为可以自定义添加维 ...

  6. 按计划员自动带出对应任务类型

    应用 Oracle   Manufacturing Planning 层 Level Function 函数名 Funcgtion Name MRPFPPWB-390 表单名 Form Name MR ...

  7. 【MM小贴士】SAP创建成本中心采购订单带出默认会计科目和成本中心

    在实施SAP项目梳理MM模块业务需求的时候,很多公司都会有这样需求,就是在创建成本中心采购订单的时候,因为成本中心和会计科目是必须输的,所以用户希望系统能够自动带出默认的会计科目和成本中心(如下图). ...

  8. Customers带出功能JS

    customerNameChange: function (event, value) { //选择客户带出销售顾问(签单顾问) .来源顾问 //先判断客户是不是为空 if (value.curren ...

  9. 区块链将颠覆游戏业,游戏内商品未来也可带出游戏、自由交易

    区块链,比特币以及其他加密货币的底层技术,不仅会改变我们的支付方式,也会改变我们玩游戏的方式. 为了更好地理解我上面所说的话,我们需要回到27年前去一探究竟. 现在是1991年马尼拉(菲律宾首都)的一 ...

最新文章

  1. 2020年班级管理html,2020年七年级班主任工作计划
  2. c++原型模式(Prototype)
  3. 在ubuntu下使用Eclipse搭建Hadoop开发环境
  4. 深度解密Go语言之Slice
  5. superset docker方式安装
  6. mac地址漂移flapping的前因后果
  7. Sql分页两种常用算法
  8. 11.6 ConfigParser模块
  9. Exchange 2013CU17和office 365混合部署-设置属性筛选(三)
  10. 2.nginx 配置
  11. linux lsnrctl命令不存在,linux – oracle lsnrctl TNS-12545:连接失败,因为目标主机或对象不存在...
  12. 九节点潮流计算matlab,(完整版)电力系统分析大作业matlab三机九节点潮流计算报告...
  13. php 转通达信数据格式,[转载]通达信数据接口及日线数据格式
  14. Android 内存映射mmap浅谈
  15. ABBYY2022PDF个人版
  16. Qt示例程序打开失败,出现一个感叹号图标
  17. html字体库otf文件使用,在webpack中加载.otf字体文件的正确方法是什么?
  18. 浅谈动态规划 ——by cbw
  19. [转载] iframe嵌入网页的用法
  20. 机房收费管理程序c语言,C语言机房收费管理系统

热门文章

  1. 两步教你轻松写出时事热点型软文营销文案
  2. Java免流量浏览器_流量费白菜价:腾讯王卡福利再升级,QQ浏览器开启全网免流量功能...
  3. HTTPS SSL证书
  4. 说一说logically exclusive 和 physically exclusive
  5. 二手小米手机价格表图片(2022.2.21)
  6. 最全的C#图片处理类ImageHelper.cs(个人保留)
  7. 基于AR9331(MIPS架构)分析系统启动过程(uboot)
  8. BootStrap框架的优缺点
  9. 网页title图标设置
  10. 华为S5720交换机通过ACL限制VLAN之间的访问