如何调整代码适配Angular 10?Angular7升级后组件报错修复
修复Angular 10下DateTimeComponent的兼容性问题
我来帮你解决升级到Angular 10后组件失效的问题,咱们针对报错逐一修复:
一、解决"Your minutes - X doesn't match your minutesGap - Y"错误
这个报错是因为新版ngx-material-timepicker新增了分钟值与minutesGap的严格校验,同时你的原代码存在两个问题:
- 直接修改了传入的
date对象,可能导致外部数据被意外篡改 - 分钟调整逻辑没有处理超过59的情况(比如
minutesGap=5,当前分钟58时,计算后会得到60,超出分钟最大值)
修改ngModel setter逻辑
替换原有的set ngModel方法,改为操作日期副本并确保分钟值合法:
set ngModel(date: Moment) { if (!date) { // 处理空值,避免组件崩溃 const defaultDate = moment(); this._ngModel = defaultDate; this.timePart = defaultDate.clone(); this.datePart = defaultDate.clone(); this.ngModelChange.emit(defaultDate); return; } // 创建日期副本,不修改外部传入的对象 const clonedDate = date.clone(); let adjustedMinutes = clonedDate.minutes(); // 计算符合minutesGap的分钟数,确保值在0-59之间 adjustedMinutes = Math.floor((adjustedMinutes + this.minutesGap - 1) / this.minutesGap) * this.minutesGap; if (adjustedMinutes >= 60) { adjustedMinutes -= 60; clonedDate.add(1, 'hour'); } clonedDate.minutes(adjustedMinutes); this.timePart = clonedDate.clone(); this.datePart = clonedDate.clone(); this._ngModel = clonedDate; this.ngModelChange.emit(clonedDate); }
二、解决"Cannot read property 'nativeElement' of undefined"错误
这个错误是因为timePart初始值设为空字符串,新版ngx-material-timepicker初始化时需要绑定有效的Moment对象或合规时间字符串,空值会导致组件无法正确获取DOM元素。
修改变量初始值
把timePart和datePart的初始值改为与_ngModel一致的Moment对象:
// 替换原有的空字符串初始值 timePart: Moment = moment(); datePart: Moment = moment(); // 同时在ngOnInit里同步初始值 ngOnInit(): void { this.timePart = this._ngModel.clone(); this.datePart = this._ngModel.clone(); }
三、补充依赖版本适配
Angular 10对依赖库版本有严格要求,你需要确保以下依赖版本匹配:
- 升级
ngx-material-timepicker到支持Angular 10的版本:
npm install ngx-material-timepicker@5.5.1 --save
- 确保
@angular/material版本为10.x.x:
npm install @angular/material@10.2.7 --save
- 确保
moment版本为2.29.x以上:
npm install moment@2.29.4 --save
完整修改后的组件代码
component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import * as moment from 'moment'; import { Moment } from 'moment'; @Component({ selector: 'app-date-time', templateUrl: './date-time.component.html' }) export class DateTimeComponent implements OnInit { private _ngModel: Moment = moment(); @Input() datePlaceHolder: string = "Date"; @Input() timePlaceHolder: string = "Time"; @Input() timeFormat: number = 24; @Input() minutesGap: number = 1; timePart: Moment = moment(); datePart: Moment = moment(); constructor() { } ngOnInit(): void { this.timePart = this._ngModel.clone(); this.datePart = this._ngModel.clone(); } @Input() get ngModel(): Moment { return this._ngModel; } @Output() ngModelChange = new EventEmitter<Moment>(); set ngModel(date: Moment) { if (!date) { const defaultDate = moment(); this._ngModel = defaultDate; this.timePart = defaultDate.clone(); this.datePart = defaultDate.clone(); this.ngModelChange.emit(defaultDate); return; } const clonedDate = date.clone(); let adjustedMinutes = clonedDate.minutes(); adjustedMinutes = Math.floor((adjustedMinutes + this.minutesGap - 1) / this.minutesGap) * this.minutesGap; if (adjustedMinutes >= 60) { adjustedMinutes -= 60; clonedDate.add(1, 'hour'); } clonedDate.minutes(adjustedMinutes); this.timePart = clonedDate.clone(); this.datePart = clonedDate.clone(); this._ngModel = clonedDate; this.ngModelChange.emit(clonedDate); } timePartChange(ev: any) { const d = this._ngModel.clone(); const m = moment(ev, "LT"); d.hours(m.hours()).minutes(m.minutes()); this.ngModel = d; } datePartChange(ev: Moment) { const d = this._ngModel.clone(); ev.hours(d.hours()).minutes(d.minutes()); this.ngModel = ev; } }
.html(优化绑定语法)
<mat-form-field> <input matInput [placeholder]="datePlaceHolder" [matDatepicker]="picker" [(ngModel)]="datePart" (ngModelChange)="datePartChange($event)"/> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker #picker></mat-datepicker> </mat-form-field><br/> <mat-form-field> <input matInput [placeholder]="timePlaceHolder" [format]="timeFormat" readonly [(ngModel)]="timePart" (ngModelChange)="timePartChange($event)" [ngxTimepicker]="timepicker"/> <ngx-material-timepicker-toggle matSuffix [for]="timepicker"></ngx-material-timepicker-toggle> <ngx-material-timepicker [minutesGap]="minutesGap" #timepicker></ngx-material-timepicker> </mat-form-field>
内容的提问来源于stack exchange,提问作者Jeet
相关产品推荐
相关产品推荐

