【问题标题】:Why does cdk overlay data refresh require 3 clicks to refresh?为什么cdk覆盖数据刷新需要3次点击才能刷新?
【发布时间】:2020-06-09 18:51:24
【问题描述】:

我创建了一个角度覆盖组件来显示有关打开覆盖组件的卡片的信息(通过单击卡片中的信息按钮);打开时,它会进行 API 调用以从 API 中检索一些数据,并在单击时传递参数。当前行为需要点击两三下才能显示正确的数据:

  • 如果是页面加载后的第一次点击,则会引发错误。 (数据已检索但未显示。覆盖未打开。我已将错误粘贴在下面)
  • 再次点击请求数据,打开覆盖并显示数据。
  • 单击不同的卡需要 3 次尝试才能获得要显示的正确数据。
    • 首次点击请求新数据并打开覆盖以前的卡片数据。
    • 第二次点击页面以关闭此叠加层
    • 第三次点击再次请求新数据并打开包含新数据的叠加层。

工艺流程:

打开 > createOverlay > getOverlayConfig > attachDialogContainer > createInjector > TeamInfoOverlayComponent > 关闭

第一次点击时出错:

错误 NullInjectorError: R3InjectorError(AppModule)[InjectionToken TEAM_INFO_DIALOG_DATA -> InjectionToken TEAM_INFO_DIALOG_DATA -> InjectionToken TEAM_INFO_DIALOG_DATA]: NullInjectorError:没有 InjectionToken TEAM_INFO_DIALOG_DATA 的提供者! 在 NullInjector.get

overlay-ref.ts

import { OverlayRef } from '@angular/cdk/overlay';

export class TeamInfoOverlayRef {

  constructor(private overlayRef: OverlayRef) { }

  close(): void {
    this.overlayRef.dispose();
    console.log('in close');
  }
}

overlay.component.ts

@Component({
  selector: 'team-info-overlay',
  template: `
   <mat-card class="example-card"  class="mat-elevation-z5">
        <mat-card-header>Team Members</mat-card-header>
        <mat-card-content *ngFor="let member of team">
            <mat-card-subtitle>
                {{member.first_name + member.last_name}}    {{member.role_name}}    {{member.email}}    {{member.total_chapters}}    {{member.added}}    {{member.tc_accepted}}
            </mat-card-subtitle>
        </mat-card-content>
   </mat-card>
    `,
    styles: [`
    :host {
      display: flex;
      flex-direction: column;
      align-items: center;
    }

    h1 {
      margin: 0;
      padding: 1em;
    }

    img {
      width: 100%;
      max-width: 500px;
      height: auto;
    }

    .overlay-content {
      padding: 1em;
    }
  `]
})
export class TeamInfoOverlayComponent {

  constructor(
    public dialogRef: TeamInfoOverlayRef,
    @Inject(TEAM_INFO_DIALOG_DATA) public team: any) {
      console.log('in TeamInfoOverlayComponent constructor');
    }
}

overlay.service.ts

interface TeamInfoDialogConfig {
  panelClass?: string;
  hasBackdrop?: boolean;
  backdropClass?: string;
  Organizers?: Organizers[];
}

const DEFAULT_CONFIG: TeamInfoDialogConfig = {
  hasBackdrop: true,
  backdropClass: 'dark-backdrop',
  panelClass: 'tm-file-preview-dialog-panel',
  Organizers: null
}

@Injectable()
export class TeamInfoOverlayService {

  constructor(
    private injector: Injector,
    private overlay: Overlay) { 
        console.log('TeamInfoOverlayService constructor');
    }

  open(config: TeamInfoDialogConfig = {}) {
      console.log('in open');
    // Override default configuration
    const dialogConfig = { ...DEFAULT_CONFIG, ...config };

    // Returns an OverlayRef which is a PortalHost
    const overlayRef = this.createOverlay(dialogConfig);

    // Instantiate remote control
    const dialogRef = new TeamInfoOverlayRef(overlayRef);

    const overlayComponent = this.attachDialogContainer(overlayRef, dialogConfig, dialogRef);

    overlayRef.backdropClick().subscribe(() => dialogRef.close());
    // overlayRef.backdropClick().(_ => dialogRef.close());

    return dialogRef;
  }

  private createOverlay(config: TeamInfoDialogConfig) {
      console.log('in createOverlay');
    const overlayConfig = this.getOverlayConfig(config);
    return this.overlay.create(overlayConfig);
  }

  private attachDialogContainer(overlayRef: OverlayRef, config: TeamInfoDialogConfig, dialogRef: TeamInfoOverlayRef) {
      console.log('in attachDialogContainer');
    const injector = this.createInjector(config, dialogRef);

    const containerPortal = new ComponentPortal(TeamInfoOverlayComponent, null, injector);
    const containerRef: ComponentRef<TeamInfoOverlayComponent> = overlayRef.attach(containerPortal);

    return containerRef.instance;
  }

  private createInjector(config: TeamInfoDialogConfig, dialogRef: TeamInfoOverlayRef): PortalInjector {
      console.log('in createInjector');
    const injectionTokens = new WeakMap();

    injectionTokens.set(TeamInfoOverlayRef, dialogRef);
    injectionTokens.set(TEAM_INFO_DIALOG_DATA, config.Organizers);

    return new PortalInjector(this.injector, injectionTokens);
  }

  private getOverlayConfig(config: TeamInfoDialogConfig): OverlayConfig {
      console.log('in getOverlayConfig');
    const positionStrategy = this.overlay.position()
      .global()
      .centerHorizontally()
      .centerVertically();

    const overlayConfig = new OverlayConfig({
      hasBackdrop: config.hasBackdrop,
      backdropClass: config.backdropClass,
    //   panelClass: config.panelClass,
      scrollStrategy: this.overlay.scrollStrategies.block(),
      positionStrategy
    });

    return overlayConfig;
  }
}

overlay.token.ts

export const TEAM_INFO_DIALOG_DATA = new InjectionToken<Organizers>('TEAM_INFO_DIALOG_DATA');

感谢任何指导。谢谢!

【问题讨论】:

    标签: angular angular-cdk


    【解决方案1】:

    在我忘记发布之前在这里快速更新.. 对于任何可能遇到此问题的人。了解我是如何调用模态视图的:

    1. 组件 A 显示许多卡片。每张卡片都有一个信息图标 点击后会出现一个模态视图。
    2. 点击信息 图标为模态调用服务,该服务通过以下方式准备模态 收集配置设置(这包括从 api 调用返回的数据。)
      • 这是我遇到问题的地方。将配置设置传递给门户主机后,数据将返回 配置模态。
      • 第一次点击卡 A 将是空白的(调用和加载数据)。第二次点击卡片 A 显示数据。第三次点击卡片 B 显示卡 A 的数据。第四次点击显示数据 对应卡片 B。

    我花了很长时间才弄清楚这一点;不幸的是几个星期。还是想通了。临时解决方案是暂停执行几分之一秒,以允许 api 完成检索数据。我将很快发布一个使用 Promise 的更强大的解决方案。

    希望这对偶然发现这个平凡问题的人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多