[英]Manage subscriptions between Angular services and components
我正在开发一个 Web 应用程序,其中多个组件共享相似的功能。 为了避免不同组件中的代码重复,我创建了一个服务来托管这些功能。
但是,我不确定如何管理共享函数的订阅,因为它们不再是每个组件的一部分,仍然需要在服务中订阅。 理想情况下,我根本不会订阅服务,只订阅组件,但功能的性质及其目的不允许我这样做。 这些是嵌套在另一个中的 AngularFire 函数。 此结构的目的是浏览数据库的不同级别并动态填充对象。 然后使用该对象生成主表的标题部分。 级别数(列和堆叠行)取决于数据库中存在的数据,具体取决于正在查询的数据库节点。 这不是我最喜欢的处理方式,所以如果你想一个更干净的方式来做到这一点,无论如何。 请记住,实际代码比下面的示例要复杂一些。
例如,此代码生成以下对象,其对应的标题部分如下图所示:
object = {
title: 'PW100',
sections: {
section1: {
title: 'HIGH PRESSURE ROTOR',
sections: {
section1: {
title: 'HP TURBINE',
sections : {
section1: {title: 'ASS'},
section2: {title: 'GRD'},
section3: {title: 'BAL'}
}
},
section2: {
title: 'HP ROTOR',
sections: {
section1: {title: 'ASS'},
section2: {title: 'BAL'}
}
}
}
},
section2: {
title: 'LOW PRESSURE ROTOR',
sections: {
section1: {
title: 'LP TURBINE',
sections : {
section1: {title: 'ASS'},
section2: {title: 'RIV'},
section3: {title: 'GRD'},
section4: {title: 'BAL'}
}
},
section2: {
title: 'LP ROTOR',
sections: {
section1: {title: 'ASS'},
section2: {title: 'BAL'}
}
}
}
},
section3: {
title: 'POWER TURBINE PACK',
sections: {
section1: {
title: '3RD STAGE TURBINE',
sections : {
section1: {title: 'ASS'},
section2: {title: 'RIV'},
section3: {title: 'GRD'},
section4: {title: 'BAL'}
}
},
section2: {
title: '4TH STAGE TURBINE',
sections : {
section1: {title: 'ASS'},
section2: {title: 'RIV'},
section3: {title: 'GRD'},
section4: {title: 'BAL'}
}
},
section3: {
title: 'PT PACK',
sections: {
section1: {title: 'ASS'},
section2: {title: 'BAL'}
}
}
}
}
}
};
组件 A 和 B 过去具有以下结构:
export class ComponentXXClass implements OnInit, OnDestroy {
// Variable used to unsubscribe in ngOnDestroy()
$unsubscribe = new Subject();
constructor(private afs: AngularFirestore) {}
ngOnInit(): void {
this.functionA().then(result => {
// Use promise's result (which is an object) to generate the table's headers section
});
}
ngOnDestroy(): void {
this.$unsubscribe.next();
this.$unsubscribe.complete();
}
functionA() {
const objectToPopulateOnEachLevel = {};
return new Promise((resolve) => {
this.afs.collection('collectionName')
.snapshotChanges()
.pipe(takeUntil(this.$unsubscribe))
.subscribe(level1VariableRequiredToAccessLevel2 => {
level1VariableRequiredToAccessLevel2.forEach(level1Var => {
// Store relevant information found at this level of the query
objectToPopulateOnEachLevel['level1'] = level1Var.payload.doc.data()['variableOfInterest'];
this.afs.collection(level1Var.payload.doc.ref.path + '/path1')
.snapshotChanges()
.pipe(takeUntil(this.$unsubscribe))
.subscribe(level2Variable => {
level2Variable.forEach(level2Var => {
// Store relevant information found at this level of the query
objectToPopulateOnEachLevel['level2'] = level2Var.payload.doc.data()['variableOfInterest'];
});
resolve(objectToPopulateOnEachLevel);
});
});
});
});
}
}
服务 :
export class Service {
// Variable used to unsubscribe in components' ngOnDestroy()
$unsubscribe = new Subject();
constructor(private afs: AngularFirestore) {}
functionA(parentPath: string, childPath: string) {
const objectToPopulateOnEachLevel = {};
return new Promise((resolve) => {
this.afs.collection(parentPath)
.snapshotChanges()
.pipe(takeUntil(this.$unsubscribe))
.subscribe(level1VariableRequiredToAccessLevel2 => {
level1VariableRequiredToAccessLevel2.forEach(level1Var => {
// Store relevant information found at this level of the query
objectToPopulateOnEachLevel['level1'] = level1Var.payload.doc.data()['variableOfInterest'];
this.afs.collection(level1Var.payload.doc.ref.path + '/' + childPath)
.snapshotChanges()
.pipe(takeUntil(this.$unsubscribe))
.subscribe(level2Variable => {
level2Variable.forEach(level2Var => {
// Store relevant information found at this level of the query
objectToPopulateOnEachLevel['level2'] = level2Var.payload.doc.data()['variableOfInterest'];
});
resolve(objectToPopulateOnEachLevel);
});
});
});
});
}
}
组件 A 和 B:
export class ComponentXXClass implements OnInit, OnDestroy {
constructor(private _service: Service) {}
ngOnInit(): void {
this._service.functionA('parentPathString', 'childPathString').then(result => {
// Use promise's result (which is an object) to generate the table's headers section
});
}
ngOnDestroy(): void {
this._service.$unsubscribe.next();
this._service.$unsubscribe.complete();
}
}
这有效,但不完全。 我的意思是数据正确显示,但似乎即使我没有退出组件 A(例如),订阅似乎并不活跃。 在组件 A 中,我尝试在服务中订阅的节点处更新数据库中的变量。 预期的行为是让订阅触发并向组件 A 发出一个新值。例如,在上面的示例中(对象及其相应的标题显示在图像中),如果我进入数据库并更改“HIGH PRESSURE ROTOR”到"NO PRESSURE ROTOR" ,我希望订阅在服务中触发,通过在承诺中重新创建对象来获取更改,并将其重新发送给组件 A,然后组件 A 将重新呈现表头。 然而,这不会发生。 我还尝试删除“取消订阅”部分,看看我处理取消订阅的方式是否是原因。 结果是一样的。
有什么想法吗?
谢谢
您必须使用 observables 来管理数据readonly objectPopulatedSubject = new BehaviorSubject({})
的状态,您还必须创建一个属性来访问 observable readonly objectPopulated$ = objectPopulatedSubject.asObservable()
并且您必须创建一个方法更新主题并为您的订阅发出新值updateObjectPopulated(data: YourType) { this.objectPopulatedSubject.next(data)}
并且在您的组件中您应该订阅 objectPopulated$。
同样要管理订阅,您应该遵循以下说明:创建订阅属性objectPopulatedSubscription: Subscription;
然后在你的 ngOnInit this.objectPopulatedSubscription = this.yourservice.objectPopulated$.subscribe(data => {//put here your logic})
并在你的 ngOnDestroy 中把this.objectPopulatedSubscription.unsubscribe()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.