angular实战记录(超详细!)服务 接口 时间戳 路由 get请求 表格行合并 枚举 管道 自定义表单验证等!

angular实战踩坑记录

本文记录了一下本人学习了angular框架以后,首次生产开发踩的坑,因为是学得很急,基本上是边学边开发。开发的是一个轧辊管理的系统,写了不少界面,感觉还是实战提升比较大哈哈哈。
因为是纯新手,所以文章可能存在问题,请友善交流。
大概会涉及以下几个知识点:
service interface 时间戳 路由 三元表达式 接口数组嵌套以及html实现 区分id路由 代码规范 string与number转化 嵌套显示数组子元素 rowSpan行合并 Router和ActivatedRoute input输入限制为数字以及正数 自定义表单验证 生命周期(数据undefined) 枚举、管道

正文开始

1. 接口发送是post 获取是get get也会有参数

// 入炉作业清单-装炉计划查询 get
inquirePlans(params: PlansInquiry): Observable<Pagination<FurnaceList>> {
	return this.http.get<Pagination<FurnaceList>>(API.PLANS, {params});
}

freight是参数类型,调用post方法 返回调用后的值 Observable是请求数据的异步请求 其中<>是他的调用get的参数类型 接口<泛型> ,return一个调用完get方法后得到的值

接口中类型有对象(object),有数组(array),注意写的格式也不同,比如

类型形式
对象area: Area
数组link: Link [ ]

同时在mock模拟数据的时候也是如此 是数组的比如pagination就加个[{ }] ,是对象的就直接写 { }

2. interface问题
① 有分页的时候注意在参数中加入pagination,没有的时候直接写接口。mock模拟数据没有分页的话,就直接写个方括号,里面是数据,比如:
在这里插入图片描述
② 若get接口带参数,不明原因报错可以在定义接口的时候加个extends HttpParams,不带参数就直接写一个params,比如

// 入炉作业操作-显示 get
inquireLinks(params): Observable<Pagination<LinkInquiry>> {
	return this.http.get<Pagination<LinkInquiry>>(API.PUT_LINK, {params});
}

③ 如果请求中需要含有id之类的额外参数,比如修改或者删除,参数是id(或id数组)并在api后面加 /${id}

// 获取修改日志列表详情
modifyListGet(id: number): Observable<ModifyDetails<ModifyList>> {
	return this.http.get<ModifyDetails<ModifyList>>(API.MODIFICATION_LIST + `/${id}`);
}

③ 删除的时候直接用delete

/* 轧辊货号管理-删除货号 */
deleteFreight(id: number): Observable<ResponseResult> { // 删除货号
return this.http.delete<ResponseResult>(API.FREIGHT + `/${id}`);
}

④ 没有响应内容时,observable里面的类型可以用any

// 入炉作业操作-保存轧辊入炉 post
savePutFreight(putWork: SavePutWork): Observable<any> {
return this.http.post<any>(API.FREIGHT_SAVE, putWork);
}

⑤ http.request 类型是可选方法的,包括delete、get、post 感觉不咋用

// 入炉作业操作-显示 get
inquireLinks(id: number): Observable<Pagination<FurnaceList>> {
return this.http.request<Pagination<FurnaceList>>('delete', API.PUT_LINK + `/${id}`);
}

⑥订阅接口数据的时候可以用这中方式接收

tableData: DetailInquiry;

this.enterFurnaceService.inquireDetail({detailId: this.detailId}).subscribe((data) => {
this.tableData = data;
});
1. 时间转换 时间戳

时间戳转换为时间
时间戳 | date:'yyyy-MM-dd HH:mm:ss’
时间转换应该用时间戳传递 再格式转换显示

在这里插入图片描述
在这里插入图片描述
时间转化为时间戳
在这里插入图片描述
传时间的时候如果未选中,默认会变成NaN这个时候应该加个判断变成

nullcreatedDt: (new Date(this.createdDate).getTime()) ? (new Date(this.createdDate).getTime()) : null,

路由

一般路由传值
① routerLink = ‘url’
② [routerLink] = “[url, key]” key不一定必须有
③ 子路由获取id
通过订阅的方式获取路由id
this.route.params.subscribe(data => {
this.linkId = data.id;
console.log(this.linkId);});
通过snapshot的方式获取id
if (data && data.length){
this.detailId = this.route.snapshot.params.id;
}
方法一: 适用于有可观察对象的 需要订阅的
constructor里写 private route: ActivatedRoute,
ngInit中写

this.route.params.subscribe(data => {
	this.linkId = data.id;
	console.log(this.linkId);
});

方法二:
constructor里写 private route: ActivatedRoute,
ngInit中写

 console.log(this.route.snapshot.params.id);

想要给路由加id
① 在path的末尾加上 /:id
在这里插入图片描述
② 给 路由传过值去
在这里插入图片描述

子路由

默认路由是redirectTo
百度一下pathMatch的作用
breadcrumb是面包屑 一般用于左上角的导航

npm

前段的npm要在ui界面下执行 如果报错 记得先看cd目录文件!!!

常用表达式

① 三元表达式
判断式 ? a : b
在这里插入图片描述

代码规范

① 没用的代码删掉
② if这种代码注意 不存在的时候
③ 前端也会用递归的数据结构 要优雅
④ 加类型 加注释

前端问题

① 当接口中数组套数组的时候 用ng-container 来 ng-for,把数组都显示出来 一直for循环到最底层子元素
在这里插入图片描述
在这里插入图片描述

② html中?的作用

/* TypeScript
  当 product没有值的时候,不访问其 price属性,
  当 product有值的时候再去访问其 price属性
*/
product?.price
<td [colSpan]="10">{{ delongTable.tableData[0]?.remark }}</td>

③ 合并行列
[rowSpan]="link.details.length"
如果是数组嵌套多个数组 不知道具体的长度 需要累加
(1)在接口中定义一个长度的属性 这个属性写在最顶层(底下有很多嵌套数组)

technician: Technician; // 技术员
links: Links[]; // 计划内环节
totalTr?: number; // 计算当前子元素的行数
(2)在ts文件中循环forEach获得最底层的子元素的个数 赋值给最顶层的totalTr属性
this.delongTable.tableData.forEach(
  item => {
    let total = 0;
    item.links.forEach(
      link => {
        link.details.forEach(
          detail => {
          total++;
        }
      );
    }
  );
  item.totalTr = total;
 }
);

(3) 在html中为rowSpan赋值

<td *ngIf="detailIndex == 0" [rowSpan]="link.details.length">{{ link.name }}</td>

④ 栅格布局
在行级元素加 nz-row 在列加nz-col 以及 nzSpan=“8”
共分为24份,8代表三分之一

<div class="furnace-item" nz-row *ngFor="let furItem of furNo; let furItemIndex = index">
<ul nz-col nzSpan="8">
<li (click)="selectFurnace(1)">a</li>
</ul>

⑤ 有时候代码报错显示没有这个数据或未定义,是由于接口传递过来的数据是异步的,不一定有值,需要加一个ngIf 和 ?

<tbody *ngIf="tableData?.freights">
<tr *ngFor="let freight of tableData.freights; let freightIndex = index">

⑥ input限制为数字以及正数,以及相应的格式
方法一: 自定义表单验证 + 正则表达式

⑦ 空格
 

一 直接使用

materialCode: [this.freight.materialCode, [ Validators.required, Validators.pattern(/^\d+(\.\d+)?$/) ]],

二 定义自定义表单
1)js中调用方法
① constructor中加

private fb: FormBuilder,
size: [this.freight.size, [ Validators.required, this.confirmNetWeight]],

② 定义 GroupForm

checkReading: FormGroup;

③ ngInit中写表单验证

this.checkReading = this.fb.group(
{
	furnaceReading: [null, [ Validators.required , this.checkNum ]]
}
);

2)定义自定义表单
输入 数字 * 数字 * 数字

private confirmNetWeight(control: FormControl): { [ key: string ]: boolean} {
if (!/^\d+\*\d+\*\d+$/.test(control.value)) {
	return { weightError: true};
}
return null;
}

输入 数字 ()? 表示可能有,可能没有

private confirmSize(control: FormControl): { sizeError: boolean } {
if (!control.value) { // 如果输入为空则返回空,相当于去空格
	return null;
}
if (!/^\d+(\.\d+)?$/.test(control.value)) {
	return { sizeError: true};
}
return null;
}

3)html中使用

<nz-form-explain *ngIf="freightForm.get('size').hasError('weightError')">请输入直径*辊身长度*总长度</nz-form-explain>

或者: 注意要在最外侧加一个[formGroup]="checkReading"
里层包裹的是 nz-form-control

<div class="reading-group" nz-form [formGroup]="checkReading">
<nz-form-control style="width: 100%">
<input type="text"
	[(ngModel)]="readingText"
	[disabled]="readOnly"
	nz-input
	placeholder="请输入电表读数"
	formControlName="furnaceReading"
	id="furnaceReading"
>
<nz-form-explain *ngIf="checkReading.get('furnaceReading').hasError('isNum')">请输入数字</nz-form-explain>
</nz-form-control>
<button nz-button nzType="primary" (click)="saveReading()" [disabled]="readOnly">保存</button>
</div>

方法二:
加一个 type="number ",设置最小数值 min=“0”, 加入下面这句话来取消字母的输入

onKeypress="return (/[\d.]/.test(String.fromCharCode(event.keyCode)))"

缺点: 科学计数法e也将无法输入,右边多了一个上下的箭头
改进: 在正则表达式里更改允许输入的字符 d是纯数字,加个点能输入浮点数

/[\d.e]/

正则表达式
验证数字:1$
验证n位的数字:^\d{n}$
验证至少n位数字:^\d{n,}$
验证m-n位的数字:^\d{m,n}$
验证零和非零开头的数字:^(0|[1-9][0-9]
)$
验证有两位小数的正实数:2+(.[0-9]{2})?$
验证有1-3位小数的正实数:3+(.[0-9]{1,3})?$
验证非零的正整数:^+?[1-9][0-9]$
验证非零的负整数:^-[1-9][0-9]
$
验证非负整数(正整数 + 0) ^\d+$
验证非正整数(负整数 + 0) ^((-\d+)|(0+))$
验证长度为3的字符:^.{3}$
验证由26个英文字母组成的字符串:4+$
验证由26个大写英文字母组成的字符串:5+$
验证由26个小写英文字母组成的字符串:6+$
验证由数字和26个英文字母组成的字符串:7+$
验证由数字、26个英文字母或者下划线组成的字符串:^\w+$
验证用户密码:8\w{5,17}$ 正确格式为:以字母开头,长度在6-18之间,只能包含字符、数字和下划线。
验证是否含有 ^%&’,;=?KaTeX parse error: Can't use function '\"' in math mode at position 1: \̲"̲ 等字符:[^%&',;=?\x22]+
验证汉字:9,{0,}$
验证Email地址:^\w+[-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)$
验证InternetURL:^http://([\w-]+.)+[\w-]+(/[\w-./?%&=]
)?$ ;10+://(w+(-w+))(.(w+(-w+)))(?S)?$
验证电话号码:^((\d{3,4})|\d{3,4}-)?\d{7,8}KaTeX parse error: Undefined control sequence: \d at position 99: …证号(15位或18位数字):^\̲d̲{15}|\d{}18
验证一年的12个月:^(0?[1-9]|1[0-2])$ 正确格式为:“01”-“09”和“1”“12”
验证一个月的31天:^((0?[1-9])|((1|2)[0-9])|30|31)$ 正确格式为:01、09和1、31。
整数:^-?\d+$
非负浮点数(正浮点数 + 0):^\d+(.\d+)?$
正浮点数 ^(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9]))$
非正浮点数(负浮点数 + 0) ^((-\d+(.\d+)?)|(0+(.0+)?))$
负浮点数 ^(-(([0-9]+.[0-9][1-9][0-9])|([0-9][1-9][0-9].[0-9]+)|([0-9][1-9][0-9])))$
浮点数 ^(-?\d+)(.\d+)?$

number与string互相转换

① string转number
方法一: parseInt(value) 或者 parseFloat(value)
方法二: Number(value) 这个在html和ts中都可用

② number转string
value.toString()

1. 

对数据在服务中进行处理

使用管道 以及 tap

// 入炉作业清单-装炉计划查询 get
inquirePlans(params: PlansInquiry): Observable<Pagination<Plans>> {
return this.http.get<Pagination<Plans>>(API.PLANS, {params}).pipe(
tap(
pagination => {
	pagination.content.forEach(
		item => {
			let total = 0;
			item.links.forEach(
			link => {
				link.details.forEach(
					detail => {
						total++;
					}
				);
			}
		);
	item.totalTr = total;
	}
);
}
));
}

Router和ActivatedRoute

① Router
路由中的信息存放在Router中 比如路径 url
可以通过切分来获取URL中的数据,此处应用是:获取了路由路径来判断是出炉还是入炉,从而决定putOrTake
这样就可以获取 具体的路径 split切分完以后的数组从1开始,0是空

url: "/enterFurnace/operation/1"
const path = this.router.url.split('/')[1];

在这里插入图片描述

② ActivatedRoute
动态路由参数 路由传参时使用 可以从中获得传递给子路由的id等参数,详情见上文

this.detailId = this.route.snapshot.params.id;

在这里插入图片描述

接口枚举类型
接口中使用

status: RollStatus; // 入厂0 在厂1 报废 2 转辊 3

枚举定义

export enum RollStatus {
	ENTER = '0', // 入厂
	IN = '1' , // 在厂
	SCRAP = '2', // 报废
	CHANGE = '3' // 转辊
}

具体使用
status.ENTRY == ‘0’ 之类的或者pipe管道

@Pipe({name: 'rollStatus'})
export class RollStatusChange implements PipeTransform {
	transform(value: RollStatus): string {
		switch (value) {
			case RollStatus.ENTER: return '入厂';
			case RollStatus.IN: return '在厂';
			case RollStatus.SCRAP: return '报废';
			case RollStatus.CHANGE: return '转辊';
		}
	}
}

  1. 0-9 ↩︎

  2. 0-9 ↩︎

  3. 0-9 ↩︎

  4. A-Za-z ↩︎

  5. A-Z ↩︎

  6. a-z ↩︎

  7. A-Za-z0-9 ↩︎

  8. a-zA-Z ↩︎

  9. \u4e00-\u9fa5 ↩︎

  10. a-zA-z ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值