Angular 循环依赖警告

标签 angular ionic-framework

tl; dr:向下滚动到解决方案

我有一个循环依赖,我收到了一个警告,这是理所当然的,但是,我正在管理它。问题是我有一个聊天组件。在 Angular 落,您可以选择查看他们的个人资料页面,而在他们的个人资料页面中,您可以选择向他们发送消息,因此是循环依赖。我正在管理这个

聊天组件

public async openProfile(): Promise<void> {
  this.modalCtrl.dismiss(); //closing the chat component before opening the profile modal
  const profile = await this.modalCtrl.create({
    component: ProfileComponent,
  });
  await profile.present();
} 

profile.component

public async openChat(): Promise<void> {
  this.modalCtrl.dismiss(); //closing the profile component before opening the chat modal
  const chat = await this.modalCtrl.create({
    component: ProfileComponent,
  });
  await chat.present();
} 

有没有更简单的方法来处理这种循环依赖?

更新:
根据下面的建议,我尝试创建服务。但是现在我有一个三向依赖圈:

聊天组件

private modalService: ModalService;

constructor(modalService: ModalService){
  this.modalService = modalService
}

public async openProfile(): Promise<void> {
  this.modalService.openProfile(this.userData);
} 

profile.component

private modalService: ModalService;

constructor(modalService: ModalService){
  this.modalService = modalService
}

public async openChat(): Promise<void> {
  this.modalService.openChat(this.userData);
}

模态服务

import { ModalController } from '@ionic/angular';
import { Injectable } from '@angular/core';
import { ProfileComponent } from '../../components/profile/profile.component';
import { ChatComponent } from '../../components/chat/chat.component';
import { UserData } from '../../interfaces/UserData/userData.interface';

@Injectable({
  providedIn: 'root',
})
export class ModalService {
  private modal: ModalController;
  public constructor(modal: ModalController) {
    this.modal = modal;
  }

  public async openProfileComponent(user: UserData): Promise<void> {
    this.modal.dismiss();
    const profile = await this.modal.create({
      component: ProfileComponent,
      componentProps: {
        contact: user,
      },
    });

    await profile.present();
  }

  public async openChatComponent(user: UserData): Promise<void> {
    this.modal.dismiss();
    const chat = await this.modal.create({
      component: ChatComponent,
      componentProps: {
        contact: user,
      },
    });

    await chat.present();
  }

  public close(): void {
    this.modal.dismiss();
  }
}


更新 Stackblitz 对 Ionic 4 来说太不稳定了,所以我无法在它上面复制,所以这里是 gist与信息和相关代码。

更新2
我接受了答案中提到的建议,但仍然出现错误。为此,我创建了一个 shared.module.ts看起来像这样:

import { UserService } from './componentServices/user/user.service';
import { ModalService } from './componentServices/modal/modal.service';
import { AuthenticationSecurityService } from './componentServices/auth_security/authentication-security.service';
import { AuthGuardService } from '../_guards/auth-guard.service';
import { ApiService } from './componentServices/api/api.service';
import { ChatService } from './components/chat/socketIO/chat.service';

@NgModule({
  imports: [CommonModule, ReactiveFormsModule, IonicModule.forRoot(), FormsModule, IonicModule],
  declarations: [
    // various components
  ],
  exports: [
    // various components and common modules
  ],
})
export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [
        UserService,
        ModalService,
        DashboardService,
        AuthenticationSecurityService,
        AuthGuardService,
        ApiService,
        ChatService,
      ],
    };
  }
}

app.module.ts
imports: [
    SharedModule.forRoot(),
]
client:135 Circular dependency detected:
src/sharedModules/componentServices/modal/modal.service.ts -> src/sharedModules/components/profile/profile.component.ts -> src/sharedModules/componentServices/modal/modal.service.ts

client:135 Circular dependency detected:
src/sharedModules/components/chat/chat.component.ts -> src/sharedModules/components/search/search.component.ts -> src/sharedModules/components/profile/profile.component.ts -> src/sharedModules/componentServices/modal/modal.service.ts -> src/sharedModules/components/chat/chat.component.ts

client:135 Circular dependency detected:
src/sharedModules/components/profile/profile.component.ts -> src/sharedModules/componentServices/modal/modal.service.ts -> src/sharedModules/components/profile/profile.component.ts

client:135 Circular dependency detected:
src/sharedModules/components/search/search.component.ts -> src/sharedModules/components/profile/profile.component.ts -> src/sharedModules/componentServices/modal/modal.service.ts -> src/sharedModules/components/chat/chat.component.ts -> src/sharedModules/components/search/search.component.ts

解决方案

正如@bryan60 和@Luis 所说,必须有一个缓冲区,所以我所做的就是遵循他们都建议的发射路线。 Bryan 给出了更多代码的样子,Luis 给出了一个很好的责任总结。这是我重构它的方式:

app.component.ts

  public initializeApp(): void {
    this.platform.ready().then((): void => {
      this.statusBar.styleDefault();
      this.splashScreen.hide();
      this._subToObservables();
    });
  }

  private _subToObservables(): void {
    this.modalService.openModal$.subscribe(
      async (e: ModalEmitInterface): Promise<void> => {
        const { command, data } = e;
        switch (command) {
          case 'open-profile':
            const profile = await this.modalCtrl.create({
              component: ProfileComponent,
              componentProps: {
                contact: data,
              },
            });
            await profile.present();
            break;

          case 'open-chat':
            // same as above
            break;

          default:
            break;
        }
      },
    );
  }

modalSignal.service.ts

export class ModalService {
  private openModalSubject: Subject<ModalEmitInterface> = new Subject<ModalEmitInterface>();
  public readonly openModal$: Observable<ModalEmitInterface> = this.openModalSubject.asObservable();

  private emitPayload: ModalEmitInterface;
  public openProfileComponent(user: UserData): void {
    this.emitPayload = {
      command: 'open-profile',
      data: user,
    };
    this.openModalSubject.next(this.emitPayload);
  }

  // repeat for others
}

聊天组件.html

<button (click)="openProfile(user)">click me</button>

聊天组件.ts

export class ChatComponent {
  public constructor(private modalSignal: ModalService){}

  private openProfile(user: UserData): void {
    this.modalSignal.openProfileComponent(user);
  }
}


就是这样,尽管您仍然需要确保关闭模态框,否则它们将继续堆叠。

最佳答案

有过几次这种情况。我每次都得到相同的解决方案,并且它对我来说非常适合,所以就这样吧。

您将需要一项服务(正如其他人所建议的那样),但也需要一个,让我们称之为公正的玩家。这个想法是使用服务作为两个相互依赖的组件之间的通信/消息缓冲区,以帮助打破交叉引用。举个例子,让我们假设“App.Component”。

组件和职责:

模态服务 :接收消息以执行操作。它可以是通过单个方法接收指示 Action 的字符串或对象,也可以是每个 Action 的多个方法。实现细节由您决定。

应用程序组件 :获取注入(inject)的 ModalService 并订阅消息事件。根据 Action 消息,然后激活相应的模态。

聊天组件 :获取注入(inject)的 Modal.Service 并发送一条消息,指示要执行的操作,即显示配置文件。

Profile.Component :获取注入(inject)的 Modal.Service 并发送消息指示要执行的操作,即发送消息。

这可以很好地扩展,并且该服务可以用作几个其他模块和/或组件之间的通信缓冲区。

关于 Angular 循环依赖警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58749172/

相关文章:

react-native - 混合 JavaScript 移动开发 - Apache Cordova vs Capacitor with Ionic vs NativeScript vs React Native

android - LiveReload ionic : ​The connection to the server was unsuccessful (http://192. 168.56.1:8100/)

angular - 如何创建配置文件(tsconfig.json、typings.json、package.json)?

javascript - 使用 ionic 根据输入文本计算价格

javascript - 如何在没有ViewChild的情况下将模板变量传递给组件

javascript - Angular cli 项目 - 更改路线时脚本未正确加载

angular - 尝试在没有表格的情况下使用 Angular Material 分页器

ionic-framework - 使用 Capacitor 在浏览器中运行 native 插件

javascript - 通过 Ionic 检测耳机

javascript - 如何在子事件触发时阻止事件(链接)