While I wouldn't classify it as strictly correct, the approach taken is more about consistency. Both methods are functional, but issues may arise due to inconsistencies in the responsibilities assigned to each component (which could also lead to testing complications).
The best practice would be to always expose a property through your controller. This ensures that each component maintains its designated responsibilities effectively. By adhering to this practice, your service can uphold its responsibilities with ease too.
@LoremIpsum mentioned a crucial issue in the comments: "your HTML not reaching stuff that's too far".
There are various scenarios related to this problem. Consider the following example with a controller named class MyController
.
Direct access property
public exposedPropertyC: number;
constructor(private serviceB: ServiceB){
this.serviceB = serviceB;
this.exposedPropertyC = this.serviceB.PropertyC;
}
Async-acquired property
public exposedPropertyC: number;
constructor(private serviceB: ServiceB){
this.serviceB = serviceB;
this.serviceB.getPropertyC().then((propertyC) => {
this.exposedPropertyC = propertyC;
});
}
Observer pattern
In certain cases, implementing the observer pattern may seem like overkill, but it offers an efficient and elegant solution.
The code snippet below showcases a simple implementation of this pattern. While there are more advanced libraries available for TypeScript utilizing this pattern, this serves as a basic outline.
Disclaimer. The observer pattern is my go-to choice, despite appearing somewhat excessive. It provides flexibility and future-proofing for data retrieval optimizations from servers, enhancing maintainability and preventing potential headaches resulting from poor design decisions ;{D
interface ObservableCallBack<T> {
(arg: T): void;
}
class Observable<T> {
public yielded: T;
public observers: ObservableCallBack<T>[];
public subscribe(observableCallBack: ObservableCallBack<T>): void {
this.observers.push(observableCallBack);
if(this.yielded !== null) observableCallBack(this.yielded);
}
public notify(arg: T): void {
this.yielded = arg;
this.observers.forEach((observer) => {
observer(arg);
});
}
}
class ServiceB {
public propertyC: Observable<number>;
constructor(private http: IHttpService) {
this.propertyC = new Observable<number>();
this.http.get('').then((res) => {
this.propertyC.notify(res.data);
});
}
}
class MyController {
public propertyC: number;
constructor(private serviceB: ServiceB) {
this.serviceB.propertyC.subscribe((propertyC) => this.propertyC = propertyC);
}
}