背景
具有嵌套组件和服务的复杂Angular特征模块。顶级组件订阅了要通知的主题,并通知模块内部捕获的错误。
问题:
所有顶级组件收到错误通知(因为他们订阅了subject.next消息)并做出反应
实施的解决方案:
通过'指纹进行过滤,但这需要在所有服务中使用.catch()连接的所有方法添加指纹'参数。
例如:
...
@Injectable()
export class SharedService {
getSth (idOfWhatToGet: string, fingerprint: string) { // <<< !!! fignerprint
this.http.get('myurl')
.toPromise()
.then(a => a)
.catch(err => this.subject.next({err, fingerprint}); // <<< !!!
}
顶级组件:
...
@Component({...})
export class SomeTopLevelComponent {
@Output() onError = new EventEmitter<Error>();
private myFingerprint = 'STL_component';
...
this.subject.subscribe(errMsg => errMsg.fingerprint === 'myFingerprint ' ?
this.onError = errMsg.err); // <<< !!! fingerprint filtered
}
有没有办法辨别哪个组件称为服务?
如果不是,那么什么可能是最佳的解决方法,或者比将“指纹”更好?每个服务电话的参数?
更多详情
让我们假设一个Angular项目使用了一个功能UI模块,包括:
通常使用feature-module-exposed-elements(顶级组件):
<my-angular-project>
<feature-el-1 (onError)="callErrHandler($event)></feature-el-1>
<feature-el-2 (onError)="callErrHandler($event)></feature-el-2>
<my-angular-project>
feature-el-1和feature-el-2组件都订阅了传入的错误消息:
OnInit() {
this.subjectSubscription = this.errorService.getErrorsMessages()
.subscribe(errorMessage => this.onError.emit(errorMessage.err));
}
当发现错误时,所有服务都会发送错误:
...
doSth.then(p => ...)
.catch(err => this.errorService.sendErrorMessage({err})
错误服务的实现类似于:
@Injectable()
export class errorService {
private subject = new Subject<any>();
sendErrorMessage(message: {err: Error}) {
this.subject.next(message);
}
getErrorsMessages(): Observable<any> {
return this.subject.asObservable();
}
}
现在,<feature-el-1>
和<feature-el-2>
通过调用同一服务上的方法加载数据,让我们说getAddresses()
。接下来会发生什么:从<feature-el-1>
发起的呼叫成功,来自<feature-el-2>
的呼叫失败。但是 BOTH <feature-el-1>
和<feature-el-2>
会收到错误并将onError
事件提升(我们只想要其中一个,即 - 服务崩溃的那个,举起活动)。
要解决此问题,我们会使用&#39;指纹&#39; - 基于某些逻辑(指示下游哪个顶级组件发生错误)添加到每个服务方法调用的参数,以便暴露的顶级组件可以决定 - 是否提高接收到的错误消息。它是一个笨重而繁琐的逻辑代码体,所以所有这些都归结为主要问题 - 服务器是否可以知道(当它知道它可以传回这些知识时,比喻说)哪个组件称为他?
答案 0 :(得分:0)
您有一个名为SharedService
的服务,用于处理后端API的Http请求,并且您希望在顶级组件中侦听错误。您希望共享该服务,以便其他组件可以使用它,但您不希望共享错误。
您遇到的问题是服务何时发出错误,您不知道哪个顶级组件负责原始Http请求。
<my-angular-project>
<feature-el-1 (onError)="callErrHandler($event)></feature-el-1>
<feature-el-2 (onError)="callErrHandler($event)></feature-el-2>
<my-angular-project>
在上面的例子中;您有两个名为feature-el-1
和feature-el-2
的功能组件。每个组件只需要发出源自该组件或其中一个子组件的错误。
从SharedService
providers数组中删除NgModule
,并将其添加到每个功能组件的providers数组中。
@Component({
selector: 'feature-el-1',
providers: [SharedService],
template: '<child-feature></child-feature>'
})
export class FeatureElOneComponent {
@Output() onError: Observable<Error>;
constructor(service: SharedService) {
this.onError = service.errors;
}
}
@Component({
selector: 'feature-el-2',
providers: [SharedService],
template: '<child-feature></child-feature>'
})
export class FeatureElTwoComponent {
@Output() onError: Observable<Error>;
constructor(service: SharedService) {
this.onError = service.errors;
}
}
现在您为每个组件定义了providers: [SharedService]
,然后每个组件都会收到该服务的新实例。他们不会共享相同的服务。
现在,让我们看一下<child-feature>
组件。
@Component({
selector: 'child-feature',
template: '<span>Child Feature</span>'
})
export class ChildFeatureComponent {
constructor(service: SharedService) {
service.doSth().then((data)=>console.log(data));
}
}
两个功能模块都使用此组件,但ChildFeatureComponent
的每个实例都会收到SharedService
的不同实例。因此,当FeatureElOneComponent
内使用的子组件触发错误时,只有该功能组件才会收到错误。