tl; dr:向下滚动到解决方案
我有一个循环依赖关系,并且正在得到警告,这是正确的,但是,我正在对其进行管理。问题是我有一个聊天组件。在角落,您可以选择查看他们的个人资料页面,而在他们的个人资料页面中,您可以选择向他们发送消息,因此是循环依赖性。我正在通过
进行管理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();
}
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);
}
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();
}
}
UPDATE Stackblitz对于Ionic 4来说太不稳定了,因此我无法在上面复制它,因此这里是gist,其中包含信息和相关代码。
UPDATE2
我接受了答案中提到的建议,但仍然出现错误。为此,我创建了一个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,
],
};
}
}
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
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;
}
},
);
}
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
}
<button (click)="openProfile(user)">click me</button>
chat.component.ts
export class ChatComponent {
public constructor(private modalSignal: ModalService){}
private openProfile(user: UserData): void {
this.modalSignal.openProfileComponent(user);
}
}
就这样,尽管您仍然需要确保要关闭模式,否则它们将继续堆积。
答案 0 :(得分:3)
在那种情况下有几次。我每次都得到相同的解决方案,并且对我来说扩展性很好,所以就行了。
您将需要一项服务(由其他人建议),但也需要一个公正的参与者。想法是将服务用作两个相互依赖的组件之间的通信/消息缓冲区,以帮助打破交叉引用。为了举例,我们假设“ App.Component”。
组成和职责:
Modal.Service :接收消息以执行操作。可以通过单个方法接收指示操作的字符串或对象,也可以通过每个操作的多个方法。实施细节由您决定。
App.Component :获取ModalService注入并订阅消息事件。根据动作消息,然后激活相应的模式。
Chat.Component :获取注入的Modal.Service并发送一条消息,指示要执行的操作,即显示配置文件。
Profile.Component :获取注入的Modal.Service并发送一条消息,指示要执行的操作,即发送一条消息。
这很好地扩展,并且该服务可以用作其他几个模块和/或组件之间的通信缓冲区。
答案 1 :(得分:1)
这很烦人,但您需要包装器或多种服务。如您所见,单一服务将无法正常工作,因为显然您无法将组件导入服务,然后再将服务导入组件。那只是一个更大的圆圈。
方法1是多种服务,规模不大。创建一个ChatModalService和ProfileModalService并注入它们的对立面。很简单,如果您不做太多的话,它会起作用。 方法2是更好的IMO。在处理模态调用的组件周围放置页面包装器,就可以保持单一服务方法。创建这样的页面包装器组件:
@Component({
template: `<profile (openChat)="openChat()></profile>`
})
export class ProfilePageComponent {
openChat() {
// call your service or what have you here
}
}
为聊天组件创建一个类似的设置,并将您的个人资料/聊天组件更改为仅发出而不是调用服务(或仅在包装器中放置用于调用模式的按钮)。希望您不会经常有这种两种方式的关系。但这是可行的,因为没有将包装器导入组件中,而是将您路由到页面包装器,但是页面包装器将实例化模态中的组件。比例更好一些,但仍不理想。这里最大的好处是,在开发此应用程序时,如果给定的组件可以以页面或模式的形式出现,则在组件周围使用页面包装可能会发现更多好处,因为有时您希望组件以不同的方式位于其上下文中。如果您预见到这样做的好处,请采用这种方法。相反,您也可以将组件包装在Modal包装器中,然后实例化这些组件,而不是直接实例化这些组件。导入逻辑是相同的,并且出于相同的原因起作用,并且具有相同的上下文好处,但另一方面。
第三个选项是相似的,设置一个通用页面包装器,并稍微更改您的模式服务,以便它只是共享通用页面包装器的事件总线。这样做的原因与上述相同,并且扩展性更好,但是缺点是您无法获得以相同方式向组件中添加上下文的好处。
@Injectable()
export class ModalSignalService{
private openChatSubject = new Subject()
openChat$ = this.opopenChatSubject.asObservable()
openChat() {
this.openChatSubject.next()
}
private openProfileSubject = new Subject()
openProfile$ = this.openProfileSubject.asObservable()
openProfile() {
this.openProfileSubject.next()
}
}
然后有一个共享的页面包装器组件订阅流并处理模式实例化
@Component({
template: `<router-outlet></router-outlet>` // something like this and set up routing with components as child routes
})
export class PageWrapperComponet {
constructor(private modalSignalService: ModalSignalService) {
this.modalSignalService.openChat$.subscribe(e => this.openChatModal()) // open modal logic here
this.modalSignalService.openProfile$.subscribe(e => this.openProfileModal())
}
}
如果您一次又一次地看到此问题,请像这样一劳永逸地解决。您甚至可能已经拥有一个组件(您肯定有一个应用程序组件,虽然可能不是最好的应用程序组件)
答案 2 :(得分:0)
创建一个同时了解这两个组件的模态服务。
ModalService {
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,
});
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();
}
}
在两个组件中注入服务。
您可能需要检查multiple instance services,以便每次注入新服务时都可以使用它。
现在这两个组件彼此不认识,因此您没有循环依赖。
为了消除警告,您应该通过组件中的注入器注入
private modalService: ModalService;
public constructor(injector:Injector) {
this.modalService = injector.get(modalService);
}