如何解决Kendo-angular-dropdown升级导致错误
我最近将我的工作应用程序从Angular 6升级到Angular 7.2。
这包括升级Kendo-Angular组件/模块。
升级后,在回归测试过程中,注意到在使用模板的kendo-combobox上,我们收到以下错误:
V2: CustomExceptionHandler Error occurred TypeError: Cannot read property 'scrollToItem' of undefined
at main.js:89941
at SafeSubscriber.schedulerFn [as _next] (main.js:14671)
at SafeSubscriber.__tryOrUnsub (main.js:45229)
at SafeSubscriber.next (main.js:45167)
at Subscriber._next (main.js:45113)
at Subscriber.next (main.js:45090)
at EventEmitter.Subject.next (main.js:86078)
at EventEmitter.emit (main.js:14643)
at PopupComponent.onAnimationEnd (main.js:125483)
at main.js:125443
这似乎来自kendo-popup,但我似乎无法修复。
我试过的
升级到kendo-angular-dropdowns和kendo-angular-popup的最新版本
删除节点模块文件夹并清除npm缓存
降级到kendo-angular-dropdowns@3.4.0可以解决此问题,但是如果我升级到3.5.0或更高版本,则会返回错误。 我对如何将kendo-angular-dropdowns升级到最新版本并解决此错误感到困惑。
谢谢
package.json中的依赖项
"dependencies": {
"@angular/animations": "7.2.16","@angular/cdk": "7","@angular/common": "7.2.16","@angular/compiler": "7.2.16","@angular/compiler-cli": "7.2.16","@angular/core": "7.2.16","@angular/forms": "7.2.16","@angular/http": "7.2.16","@angular/material": "7","@angular/platform-browser": "7.2.16","@angular/platform-browser-dynamic": "7.2.16","@angular/platform-server": "7.2.16","@angular/router": "7.2.16","@ngrx/effects": "^7.4.0","@ngrx/store": "^7.4.0","@ngrx/store-devtools": "^7.4.0","@ngui/auto-complete": "0.16.0","@progress/kendo-angular-buttons": "5.4.2","@progress/kendo-angular-charts": "4.1.4","@progress/kendo-angular-common": "1.2.3","@progress/kendo-angular-dateinputs": "4.2.2","@progress/kendo-angular-dialog": "4.2.0","@progress/kendo-angular-dropdowns": "3.4.0","@progress/kendo-angular-excel-export": "3.1.3","@progress/kendo-angular-grid": "4.7.2","@progress/kendo-angular-inputs": "6.6.0","@progress/kendo-angular-intl": "2.0.1","@progress/kendo-angular-l10n": "2.0.1","@progress/kendo-angular-layout": "4.2.1","@progress/kendo-angular-pdf-export": "2.0.3","@progress/kendo-angular-popup": "3.0.6","@progress/kendo-angular-ripple": "2.0.1","@progress/kendo-angular-scrollview": "3.0.1","@progress/kendo-angular-sortable": "3.0.2","@progress/kendo-angular-tooltip": "2.1.3","@progress/kendo-angular-treeview": "4.2.0","@progress/kendo-angular-upload": "6.0.0","@progress/kendo-data-query": "1.5.4","@progress/kendo-drawing": "1.9.2","@progress/kendo-theme-default": "2.54.0","@progress/kendo-theme-material": "^1.5.0","@types/clipboard": "1.5.35","@types/file-saver": "1.3.0","@types/highcharts": "5.0.11","@types/lodash": "^4.14.62","@types/moment-timezone": "^0.5.4","angular-l10n": "7.2.0","angular-resizable-element": "^3.3.3","angular-router-loader": "0.7.0","angular2-busy": "^2.0.4","aspnet-prerendering": "3.0.1","aspnet-webpack": "1.0.29","babel-polyfill": "^6.23.0","bootstrap": "3.3.7","clipboard": "^1.6.1","compression-webpack-plugin": "1.0.1","exceljs": "3.5.0","file-saver": "1.3.3","font-awesome": "4.7.0","hammerjs": "^2.0.8","highcharts": "6.0.3","html-webpack-plugin": "^2.28.0","husky": "^0.14.3","isomorphic-fetch": "2.2.1","lodash": "^4.17.4","lscache": "1.1.0","moment": "^2.17.1","moment-timezone": "^0.5.14","ng2-appinsights": "^1.0.0-beta.1","ng2-auto-complete": "^0.12.0","ng2-dnd": "^5.0.2","ngx-bootstrap": "2.0.0-beta.1","ngx-tinymce": "^7.0.0","ngx-toastr": "8.8.0","normalize.css": "7.0.0","optimize-js-plugin": "^0.0.4","preboot": "5.1.7","rxjs": "6.6.3","rxjs-compat": "^6.6.3","zone.js": "0.8.29"
},
组件HTML
<div *ngIf="ttsConfig?.formgroup" #form="ngForm" [formGroup]="ttsConfig.formgroup">
<!--value:{{ttsConfig.formgroup.controls.counterpartyId.value}}-->
<div class="tts-wrapper" >
<span class="tts-fieldname">{{ttsConfig.translate? friendlyFieldName : ttsConfig.friendlyFieldName}}<span *ngIf="ttsConfig.required" style="padding-left:3px;">*</span></span>
<div *ngIf="!AuthInfo">
<kendo-combobox #autocomplete [id]="id"
[data]="data"
[popupSettings]="{width: ttsConfig.width,appendTo: ViewContainerRef,animate: false}"
[filterable]="true"
[formControlName]="ttsConfig.formcontrolname"
(filterChange)="callDebouncer($event)"
[valueField]="ttsConfig.apiIdName"
[textField]="ttsConfig.displayTextColoumn"
[valuePrimitive]="true"
(open)="checkMinLength($event)"
[placeholder]="ttsConfig.translate? placeholder : ttsConfig.placeholder"
[required]="ttsConfig.required"
class="{{ttsConfig.cssClass}}"
(valueChange)="onGridSelectionChange($event)">
<ng-template kendoAutoCompleteHeaderTemplate>
<table width="{{ttsConfig.width}}">
<tr>
<td *ngFor="let i of ttsConfig.columns" style="font-weight:bold"><span *ngIf="ttsConfig.translate" l10nTranslate>{{i}}</span><span *ngIf="!ttsConfig.translate">{{i}}</span></td>
</tr>
</table>
</ng-template>
<ng-template kendoAutoCompleteItemTemplate let-dataItem>
<table width="{{ttsConfig.width}}">
<tr>
<td *ngFor="let i of ttsConfig.apiDisplayObjectName">
{{ dataItem[i] }}
</td>
</tr>
</table>
</ng-template>
</kendo-combobox>
<button *ngIf="ttsConfig.displayIcon === true" #anchor (click)="toggle()" class="k-button k-button-icon" [hidden]="data.length === 0"><i class="fa fa-info" aria-hidden="true"></i></button>
<div class="custom-error-tts" *ngIf="ttsConfig.formgroup.controls[ttsConfig.formcontrolname]?.errors && ttsConfig.formgroup.controls[ttsConfig.formcontrolname].touched === true">
<strong l10nTranslate>{{ttsConfig.formgroup.controls[ttsConfig.formcontrolname].errors | errorPipe}}</strong>
</div>
</div>
<div *ngIf="AuthInfo">
<kendo-combobox #autocomplete [id]="id"
[data]="data"
[popupSettings]="{width: ttsConfig.width,animate: false}"
[filterable]="true"
[formControlName]="ttsConfig.formcontrolname"
(filterChange)="callDebouncer($event)"
[valueField]="ttsConfig.apiIdName"
[textField]="ttsConfig.displayTextColoumn"
[valuePrimitive]="true"
(open)="checkMinLength($event)"
[placeholder]="ttsConfig.translate? placeholder : ttsConfig.placeholder"
[required]="ttsConfig.required"
class="{{ttsConfig.cssClass}}"
(valueChange)="onGridSelectionChange($event)" counterpartyAccess [authInfo]="AuthInfo">
<!-- <ng-template kendoAutoCompleteHeaderTemplate>
<table width="{{ttsConfig.width}}">
<tr>
<td *ngFor="let i of ttsConfig.columns" style="font-weight:bold"><span *ngIf="ttsConfig.translate" l10nTranslate>{{i}}</span><span *ngIf="!ttsConfig.translate">{{i}}</span></td>
</tr>
</table>
</ng-template>
<ng-template kendoAutoCompleteItemTemplate let-dataItem>
<table width="{{ttsConfig.width}}">
<tr>
<td *ngFor="let i of ttsConfig.apiDisplayObjectName">
{{ dataItem[i] }}
</td>
</tr>
</table>
</ng-template> -->
</kendo-combobox>
<button *ngIf="ttsConfig.displayIcon === true" #anchor (click)="toggle()" class="k-button k-button-icon" [hidden]="data.length === 0"><i class="fa fa-info" aria-hidden="true"></i></button>
<div class="custom-error-tts" *ngIf="ttsConfig.formgroup.controls[ttsConfig.formcontrolname]?.errors && ttsConfig.formgroup.controls[ttsConfig.formcontrolname].touched === true">
<strong l10nTranslate>{{ttsConfig.formgroup.controls[ttsConfig.formcontrolname].errors | errorPipe}}</strong>
</div>
</div>
<kendo-popup #popup [anchor]="anchor" popupClass="content" *ngIf="show">
<table>
<tr>
<td *ngFor="let i of ttsConfig.columns" style="font-weight:bold"><span *ngIf="ttsConfig.translate" l10nTranslate>{{i}}</span><span *ngIf="!ttsConfig.translate">{{i}}</span></td>
</tr>
</table>
<table *ngIf="data.length > 0">
<tr>
<td style="max-height: 100px; max-width:200px; white-space:pre-wrap;" *ngFor="let i of ttsConfig.apiDisplayObjectName">
{{ data[0][i] }}
</td>
</tr>
</table>
</kendo-popup>
</div>
<span *ngIf="IsMDM">*MDM</span>
</div>
Component.ts文件
import { Component,ViewChild,Input,Output,EventEmitter,ElementRef,HostListener,OnInit,OnChanges,OnDestroy,LOCALE_ID,Inject } from '@angular/core';
import { FormGroup,FormControl,Validators,FormBuilder } from '@angular/forms';
import { AutoCompleteComponent } from '@progress/kendo-angular-dropdowns';
import { DropdownService } from '@ldc/core/shared/services';
import { takeUntil,debounceTime,distinctUntilChanged } from 'rxjs/operators';
import { Subject } from 'rxjs';
//import { TranslationService } from 'angular-l10n';
import { LdcLocale,LocaleService,TranslationService } from '@ldc/core/shared/classes/LdcLocale';
import { LocaleSubscriptionService } from '@ldc/core/shared/services';
import { CldrIntlService } from '@progress/kendo-angular-intl';
@Component({
selector: 'ldc-type-to-search',templateUrl: './type-to-search.component.html',styleUrls: ['./type-to-search.component.scss']
})
export class TypeToSearchComponent extends LdcLocale implements OnInit,OnDestroy {
@ViewChild('autocomplete') public autocomplete: AutoCompleteComponent;
@Input() ttsConfig: TypeToSearchConfig = new TypeToSearchConfig();
@Input() id: string = undefined;
@Output() public selectedItemChange: EventEmitter<any> = new EventEmitter();
@ViewChild('anchor') public anchor: ElementRef;
@ViewChild('popup',{ read: ElementRef }) public popup: ElementRef;
@Input() IsMDM = false;
@Input() AuthInfo: any;
public gridSelection: string[] = [];
public dataList: any[] = [];
public data: any[] = [];
private formSubscribed: boolean = false;
private ngUnsubscribe = new Subject();
private debouncer: Subject<any> = new Subject();
public value: any;
private toggleText = 'Show';
private show = false;
private initalLoadComplete = false;
private friendlyFieldName: string = '';
private placeholder: string = '';
constructor(@Inject(LOCALE_ID) public localeId: string,private dropdownService: DropdownService,private localeService: LocaleService,private localeSubscriptionService: LocaleSubscriptionService,private intlService: CldrIntlService,private translationService: TranslationService) {
super(localeService,translationService);
}
ngOnInit() {
this.localeSubscriptionService.currentLocaleId.pipe(takeUntil(this.ngUnsubscribe)).subscribe(localeId => this.setLocaleId(localeId));
if (this.ttsConfig.apiByTermTypeNoSearchUrl) {
this.callApi();
}
this.debouncer.pipe(takeUntil(this.ngUnsubscribe),debounceTime(100)).subscribe(event => {
this.handleFilter(event);
});
}
ngOnChanges(change) {
if (change.ttsConfig && change.ttsConfig.currentValue.formgroup !== null && this.formSubscribed === false) {
this.formSubscribed = true;
if (this.ttsConfig.formgroup.value[this.ttsConfig.formcontrolname] !== null && change.previousValue === undefined) {
this.callApi(this.ttsConfig.formgroup.value[this.ttsConfig.formcontrolname]);
}
//this was originally subscribed to the entire form and could negatively impact performance
//we need to only subscribe to the control itself
this.ttsConfig.formgroup.controls[this.ttsConfig.formcontrolname].valueChanges.pipe(takeUntil(this.ngUnsubscribe)).subscribe((val) => {
if (val !== null) {
this.callApi(val);
}
});
let formcontrolname = this.ttsConfig.formcontrolname;
let formgroup = this.ttsConfig.formgroup;
let formControlValue = formgroup.controls[formcontrolname].value;
if (this.ttsConfig.useDirectBinding === true && formControlValue !== undefined && formControlValue !== null && formControlValue !== '') {
this.callApi(formControlValue);
}
}
}
setLocaleId(localeId: string) {
this.localeId = localeId;
this.intlService.localeId = localeId;
if (this.ttsConfig.translate) {
this.translationService.init().then((data) => {
this.placeholder = this.translationService.translate(this.ttsConfig.placeholder,null,this.localeService.getCurrentLanguage());
this.friendlyFieldName = this.translationService.translate(this.ttsConfig.friendlyFieldName,this.localeService.getCurrentLanguage());
});
}
}
ngOnDestroy() {
this.ngUnsubscribe.next();
this.ngUnsubscribe.complete();
}
private callDebouncer(event) {
this.debouncer.next(event);
}
public onGridSelectionChange(val): void {
if (!val) {
this.selectedItemChange.emit({ value: null,control: this.ttsConfig.formcontrolname });
return;
}
if (this.ttsConfig.emitPrimitive) {
if (this.ttsConfig.apiUrl === 'CRS/ViewTTSGinInvoiceCounterparty/') {
let selectedobj = this.dataList.find(x => x[this.ttsConfig.apiIdName] == val);
this.selectedItemChange.emit({ value: selectedobj,control: this.ttsConfig.formcontrolname });
} else {
this.selectedItemChange.emit({ value: val,control: this.ttsConfig.formcontrolname });
}
} else {
let selectedobj = this.dataList.find(x => x[this.ttsConfig.apiIdName] == val);
this.selectedItemChange.emit({ value: selectedobj,control: this.ttsConfig.formcontrolname });
}
this.value = val;
}
handleFilter(value) {
if (value.length >= this.ttsConfig.minLength) {
this.callApi(value);
} else {
this.autocomplete.toggle(false);
}
}
checkMinLength(e) {
if (this.autocomplete.text.length >= this.ttsConfig.minLength || this.ttsConfig.apiByTermTypeNoSearchUrl) {
} else {
this.autocomplete.toggle(false);
}
}
callApi(searchTerm?) {
if (searchTerm !== undefined && searchTerm.trim().length > 0) {
let term = `${this.ttsConfig.apiUrl}${encodeURIComponent(searchTerm)}`;
this.dropdownService.getData(term,0).pipe(takeUntil(this.ngUnsubscribe)).subscribe(resp => {
this.dataList = resp;
this.data = this.dataList.slice();
const fgvalue = this.ttsConfig.formgroup.controls[this.ttsConfig.formcontrolname].value;
if (this.ttsConfig.emitInitalLoad && !this.initalLoadComplete && fgvalue) {
this.onGridSelectionChange(fgvalue);
this.initalLoadComplete = true;
}
if (this.ttsConfig.apiByTermTypeNoSearchUrl) {
this.data.sort((a,b) => a.TermDescription.localeCompare(b.TermDescription));
}
});
} else {
let term = this.ttsConfig.apiByTermTypeNoSearchUrl ? `${this.ttsConfig.apiByTermTypeNoSearchUrl}` : undefined;
if (term) {
this.dropdownService.getData(term,0).pipe(takeUntil(this.ngUnsubscribe)).subscribe(resp => {
this.dataList = resp;
this.data = this.dataList.slice();
this.data.sort((a,b) => a.TermDescription.localeCompare(b.TermDescription));
});
}
}
}
@HostListener('keydown',['$event'])
public keydown(event: any): void {
if (event.keyCode === 27) { //escape key
this.toggle(false);
}
}
@HostListener('document:click',['$event'])
public documentClick(event: any): void {
if (this.ttsConfig.displayIcon && this.data.length > 0) {
if (!this.contains(event.target)) {
this.toggle(false);
}
}
}
public toggle(show?: boolean): void {
this.show = show !== undefined ? show : !this.show;
this.toggleText = this.show ? 'Hide' : 'Show';
}
private contains(target: any): boolean {
if (this.ttsConfig.displayIcon && this.data.length > 0) {
return this.anchor.nativeElement.contains(target) ||
(this.popup ? this.popup.nativeElement.contains(target) : false);
} else {
return false;
}
}
}
export class TypeToSearchConfig {
columns: string[];
required: boolean;
apiUrl: string;
apiDisplayObjectName: string[];
displayTextColoumn: string;
apiIdName: string;
formcontrolname: string;
formgroup: FormGroup;
placeholder: string;
friendlyFieldName: string;
width: number;
cssClass: string;
displayIcon: boolean;
minLength: number;
apiByTermTypeNoSearchUrl?: string;
emitPrimitive: boolean;
emitInitalLoad: boolean;
useDirectBinding: boolean;
translate: boolean;
constructor(
columns: string[] = [],requried: boolean = false,apiUrl: string = null,apiDisplayObjectName: string[] = null,displayTextColoumn: string = null,apiIdName: string = null,fromcontrolname: string = null,formgroup: FormGroup = null,placeholder: string = '',friendlyFieldName: string = '',width: number = 750,cssClass: string = 'lc-combobox',displayIcon: boolean = true,minLength: number = 3,apiByTermTypeNoSearchUrl: string = null,translate: boolean = false) {
this.columns = columns;
this.required = requried;
this.apiUrl = apiUrl;
this.displayTextColoumn = displayTextColoumn;
this.apiDisplayObjectName = apiDisplayObjectName;
this.apiIdName = apiIdName;
this.formcontrolname = fromcontrolname;
this.formgroup = formgroup;
this.placeholder = placeholder;
this.friendlyFieldName = friendlyFieldName;
this.width = width;
this.cssClass = cssClass;
this.displayIcon = displayIcon;
this.minLength = minLength;
this.apiByTermTypeNoSearchUrl = apiByTermTypeNoSearchUrl;
this.translate = translate;
this.emitPrimitive = true;
this.emitInitalLoad = false;
this.useDirectBinding = false;
}
}
``
解决方法
所以我遇到的问题是,我不想在组合框中显示弹出窗口,直到usr在输入中输入的字符数最少为止。
以前(另一位开发人员)是通过挂钩组合框的打开事件(open)="checkMinLength($event)"
来完成此操作的
这样做的:
checkMinLength(e) {
if (this.autocomplete.text.length <= this.minLength) {
this.autocomplete.toggle(false);
}
}
我发现一个sendDocument处理类似的问题。
基本上对我来说,解决方案是将this.autocomplete.toggle(false);
替换为e.preventDefault();
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。