从 Angular 9 升级到 10 后自定义 CDK 步进器不工作
Customize CDK stepper not working after upgrade from Angular 9 to 10
最近,我按照 angular 更新指南 here 从 Angular 9 更新到 10。我更新了 core,cli,material,cdk,ngrx 等。我做了一个 'ng update' 以确保所有内容都已正确迁移。
然后我在没有任何 errors/warnings 的情况下编译并构建它,一切正常,除了 cdk stepper,它不显示任何 cdk 步骤和内容
<cdk-stepper></cdk-stepper>
图片:Angular 10
但它在 Angular 9
中工作正常
图片:Angular 9
这是我自定义的 cdk 步进器组件 .ts 和 html:
import { animate, AnimationEvent, state, style, transition, trigger } from '@angular/animations';
import { CdkStepper, StepContentPositionState } from '@angular/cdk/stepper';
import { AfterContentInit, ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
@Component({
selector: 'cdk-stepper',
templateUrl: './cdk-stepper.component.html',
styleUrls: ['./cdk-stepper.component.scss'],
providers: [{ provide: CdkStepper, useExisting: CdkStepperComponent }],
animations: [trigger('stepTransition', [
state('previous', style({
transform: 'translateY(-100%)', zIndex: -1,
opacity: 0
})),
state('current', style({
transform: 'translateY(0)', zIndex: 0,
opacity: 1
})),
state('next', style({
transform: 'translateY(100%)', zIndex: -1,
opacity: 0
})),
transition('* => *', animate('700ms cubic-bezier(0.35,0,0.25,1)'))
])],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkStepperComponent extends CdkStepper
implements AfterContentInit {
currentVerticalLine = {
'height': '20vh',
'transition': 'height 200ms ease',
'top': '-3%'
}
@Output() readonly animationDone: EventEmitter<void> = new EventEmitter<void>();
_animationDone = new Subject<AnimationEvent>();
@Input() stepHeaderNumber;
stepHeaderTitle = ['Scan Tenant', 'Mailbox Rules', 'Audit Logs', 'Summary']
@Input('setSelectedIndex') set setSelectedIndex(index: number) {
this.updateIndex(index);
}
@Output() updateMyIndex: EventEmitter<number> = new EventEmitter();
updateIndex(index: number) {
console.log(index)
this.selectedIndex = index;
this.updateMyIndex.emit(index);
}
onClick(index: number): void {
this.selectedIndex = index;
}
ngAfterContentInit() {
console.log(this.steps)
// Mark the component for change detection whenever the content children query change
this.steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => {
this._stateChanged();
});
this._animationDone.pipe(
// distinctUntilChanged to avoid emitting the same event twice,
// as some browsers callback invokes '.done' twice.
distinctUntilChanged((x, y) => {
return x.fromState === y.fromState && x.toState === y.toState;
}),
takeUntil(this._destroyed)
).subscribe(event => {
if ((event.toState as StepContentPositionState) === 'current') {
this.animationDone.emit();
}
});
}
checkProgress(index) {
if (this.selectedIndex > index) {
return true;
}
else {
return false;
}
}
}
<div class="container">
<app-vertical-steps [steps]="steps" [titles]="stepHeaderTitle" [(current)]="selectedIndex" (currentChange)="updateIndex($event)"></app-vertical-steps>
<div class="cdk-vertical-content-container">
<div *ngFor="let step of steps; let i=index;" class="cdk-vertical-content ng-trigger ng-trigger-stepTransition"
[@stepTransition]="_getAnimationDirection(i)" [attr.tabindex]="selectedIndex === i ? 0 : null"
[id]="_getStepContentId(i)" (@stepTransition.done)="_animationDone.next($event)"
[attr.aria-labelledby]="_getStepContentId(i)" [attr.aria-expanded]="selectedIndex === i">
<mat-card class="cdk-card" [class.hidden]="selectedIndex !== i">
<ng-container [ngTemplateOutlet]="step.content"></ng-container>
</mat-card>
</div>
</div>
</div>
下面是我使用 cdk-stepper 作为子组件的父组件容器:
import { Component, OnDestroy, OnInit } from "@angular/core";
import { select, Store } from '@ngrx/store';
import { combineLatest } from 'rxjs';
import { GraphActions } from 'src/app/actions';
import { fetchSummaries } from 'src/app/entities/event-summary/event-summary.actions';
import * as fromRoot from 'src/app/reducers';
@Component({
selector: "app-container",
templateUrl: "./container.component.html",
styleUrls: ["./container.component.scss"]
})
export class ContainerComponent implements OnInit, OnDestroy {
pending = false;
myIndex = 0;
constructor(
private store: Store<fromRoot.State>
) { }
ngOnInit() {
combineLatest(
this.store.pipe(select(fromRoot.getInitialized)),
this.store.pipe(select(fromRoot.inboxRulesFetched)),
this.store.pipe(select(fromRoot.getUsers))
).subscribe(([initialized, fetched, users]) => {
if (initialized) {
this.store.dispatch(fetchSummaries());
if (!fetched) {
for (let index = 0; index < users.length; index++) {
const identity = users[index].id;
const mail = users[index].mail;
if (mail !== null && users[index].userType !== 'Guest') {
this.store.dispatch(GraphActions.fetchGraphInboxRules({ identity }))
}
}
}
}
})
}
ngOnDestroy() {
}
setIndex($event) {
this.myIndex = $event;
}
setPendingScan($event) {
this.pending = $event;
}
}
<div class="container">
<app-log-scanning-icon [pendingScan]="pending"></app-log-scanning-icon>
<cdk-stepper [setSelectedIndex]="myIndex" (updateMyIndex)="setIndex($event)">
<cdk-step>
<app-introduction (indexChange)="setIndex($event)" (pendingScan)="setPendingScan($event)"></app-introduction>
</cdk-step>
<cdk-step>
<app-mailboxes (indexChange)="setIndex($event)" [currentStep]="myIndex === 1"></app-mailboxes>
</cdk-step>
<cdk-step>
<app-audit-logs (indexChange)="setIndex($event)" [currentStep]="myIndex === 2"></app-audit-logs>
</cdk-step>
<cdk-step>
<app-summary (indexChange)="setIndex($event)" [currentStep]="myIndex === 3"></app-summary>
</cdk-step>
</cdk-stepper>
</div>
如果有人能提供帮助或提供任何提示为什么它在 angular 10 上不起作用,我将不胜感激。
或者我的代码的任何部分被委托?谢谢。
P.S。这是我的 package.json 版本列表:package.json
我升级到angular10后遇到了同样的问题。它曾经给出错误,无法访问未定义的内容。基本上选择的值没有得到 set.After 多次尝试调试问题,我将 @angular/cdk 版本降级到 10.0.0 并且它有效。尝试降级 cdk 版本。最新版本有问题。
遇到了同样的问题。
问题是 CdkStepperComponent 组件中的 ngAfterContentInit() 。在版本 10 中,您必须调用 CdkStepper 父级 class 的 super.ngAfterContentInit(),显然自版本 10 以来,这些步骤已在此方法中初始化。
最近,我按照 angular 更新指南 here 从 Angular 9 更新到 10。我更新了 core,cli,material,cdk,ngrx 等。我做了一个 'ng update' 以确保所有内容都已正确迁移。
然后我在没有任何 errors/warnings 的情况下编译并构建它,一切正常,除了 cdk stepper,它不显示任何 cdk 步骤和内容
<cdk-stepper></cdk-stepper>
图片:Angular 10
但它在 Angular 9
中工作正常图片:Angular 9
这是我自定义的 cdk 步进器组件 .ts 和 html:
import { animate, AnimationEvent, state, style, transition, trigger } from '@angular/animations';
import { CdkStepper, StepContentPositionState } from '@angular/cdk/stepper';
import { AfterContentInit, ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';
import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
@Component({
selector: 'cdk-stepper',
templateUrl: './cdk-stepper.component.html',
styleUrls: ['./cdk-stepper.component.scss'],
providers: [{ provide: CdkStepper, useExisting: CdkStepperComponent }],
animations: [trigger('stepTransition', [
state('previous', style({
transform: 'translateY(-100%)', zIndex: -1,
opacity: 0
})),
state('current', style({
transform: 'translateY(0)', zIndex: 0,
opacity: 1
})),
state('next', style({
transform: 'translateY(100%)', zIndex: -1,
opacity: 0
})),
transition('* => *', animate('700ms cubic-bezier(0.35,0,0.25,1)'))
])],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CdkStepperComponent extends CdkStepper
implements AfterContentInit {
currentVerticalLine = {
'height': '20vh',
'transition': 'height 200ms ease',
'top': '-3%'
}
@Output() readonly animationDone: EventEmitter<void> = new EventEmitter<void>();
_animationDone = new Subject<AnimationEvent>();
@Input() stepHeaderNumber;
stepHeaderTitle = ['Scan Tenant', 'Mailbox Rules', 'Audit Logs', 'Summary']
@Input('setSelectedIndex') set setSelectedIndex(index: number) {
this.updateIndex(index);
}
@Output() updateMyIndex: EventEmitter<number> = new EventEmitter();
updateIndex(index: number) {
console.log(index)
this.selectedIndex = index;
this.updateMyIndex.emit(index);
}
onClick(index: number): void {
this.selectedIndex = index;
}
ngAfterContentInit() {
console.log(this.steps)
// Mark the component for change detection whenever the content children query change
this.steps.changes.pipe(takeUntil(this._destroyed)).subscribe(() => {
this._stateChanged();
});
this._animationDone.pipe(
// distinctUntilChanged to avoid emitting the same event twice,
// as some browsers callback invokes '.done' twice.
distinctUntilChanged((x, y) => {
return x.fromState === y.fromState && x.toState === y.toState;
}),
takeUntil(this._destroyed)
).subscribe(event => {
if ((event.toState as StepContentPositionState) === 'current') {
this.animationDone.emit();
}
});
}
checkProgress(index) {
if (this.selectedIndex > index) {
return true;
}
else {
return false;
}
}
}
<div class="container">
<app-vertical-steps [steps]="steps" [titles]="stepHeaderTitle" [(current)]="selectedIndex" (currentChange)="updateIndex($event)"></app-vertical-steps>
<div class="cdk-vertical-content-container">
<div *ngFor="let step of steps; let i=index;" class="cdk-vertical-content ng-trigger ng-trigger-stepTransition"
[@stepTransition]="_getAnimationDirection(i)" [attr.tabindex]="selectedIndex === i ? 0 : null"
[id]="_getStepContentId(i)" (@stepTransition.done)="_animationDone.next($event)"
[attr.aria-labelledby]="_getStepContentId(i)" [attr.aria-expanded]="selectedIndex === i">
<mat-card class="cdk-card" [class.hidden]="selectedIndex !== i">
<ng-container [ngTemplateOutlet]="step.content"></ng-container>
</mat-card>
</div>
</div>
</div>
下面是我使用 cdk-stepper 作为子组件的父组件容器:
import { Component, OnDestroy, OnInit } from "@angular/core";
import { select, Store } from '@ngrx/store';
import { combineLatest } from 'rxjs';
import { GraphActions } from 'src/app/actions';
import { fetchSummaries } from 'src/app/entities/event-summary/event-summary.actions';
import * as fromRoot from 'src/app/reducers';
@Component({
selector: "app-container",
templateUrl: "./container.component.html",
styleUrls: ["./container.component.scss"]
})
export class ContainerComponent implements OnInit, OnDestroy {
pending = false;
myIndex = 0;
constructor(
private store: Store<fromRoot.State>
) { }
ngOnInit() {
combineLatest(
this.store.pipe(select(fromRoot.getInitialized)),
this.store.pipe(select(fromRoot.inboxRulesFetched)),
this.store.pipe(select(fromRoot.getUsers))
).subscribe(([initialized, fetched, users]) => {
if (initialized) {
this.store.dispatch(fetchSummaries());
if (!fetched) {
for (let index = 0; index < users.length; index++) {
const identity = users[index].id;
const mail = users[index].mail;
if (mail !== null && users[index].userType !== 'Guest') {
this.store.dispatch(GraphActions.fetchGraphInboxRules({ identity }))
}
}
}
}
})
}
ngOnDestroy() {
}
setIndex($event) {
this.myIndex = $event;
}
setPendingScan($event) {
this.pending = $event;
}
}
<div class="container">
<app-log-scanning-icon [pendingScan]="pending"></app-log-scanning-icon>
<cdk-stepper [setSelectedIndex]="myIndex" (updateMyIndex)="setIndex($event)">
<cdk-step>
<app-introduction (indexChange)="setIndex($event)" (pendingScan)="setPendingScan($event)"></app-introduction>
</cdk-step>
<cdk-step>
<app-mailboxes (indexChange)="setIndex($event)" [currentStep]="myIndex === 1"></app-mailboxes>
</cdk-step>
<cdk-step>
<app-audit-logs (indexChange)="setIndex($event)" [currentStep]="myIndex === 2"></app-audit-logs>
</cdk-step>
<cdk-step>
<app-summary (indexChange)="setIndex($event)" [currentStep]="myIndex === 3"></app-summary>
</cdk-step>
</cdk-stepper>
</div>
如果有人能提供帮助或提供任何提示为什么它在 angular 10 上不起作用,我将不胜感激。 或者我的代码的任何部分被委托?谢谢。
P.S。这是我的 package.json 版本列表:package.json
我升级到angular10后遇到了同样的问题。它曾经给出错误,无法访问未定义的内容。基本上选择的值没有得到 set.After 多次尝试调试问题,我将 @angular/cdk 版本降级到 10.0.0 并且它有效。尝试降级 cdk 版本。最新版本有问题。
遇到了同样的问题。 问题是 CdkStepperComponent 组件中的 ngAfterContentInit() 。在版本 10 中,您必须调用 CdkStepper 父级 class 的 super.ngAfterContentInit(),显然自版本 10 以来,这些步骤已在此方法中初始化。