I can't seem to find a solution for making an entire model observable. Despite reading this post, it doesn't quite meet my requirements. I'm not looking to make individual properties observable, but rather the entire class itself. Here's what I have managed to come up with so far:
export class ObservableModel extends Observable<any> {
__internalSource = new BehaviorSubject(this);
source = this.__internalSource.asObservable();
}
/**
* Base entity class that all models should inherit from
*/
export class EntityModel extends ObservableModel {
protected entityData: AnyEntity;
protected entityState: {
loading: boolean;
loaded: boolean;
reloading: boolean;
error: boolean;
} = {
loading: false,
loaded: false,
reloading: false,
error: false,
};
constructor(public type: string, public id?: string) {}
from(value: AnyEntity) {
const { type, id } = value;
this.entityState = {
loaded: true,
loading: false,
reloading: false,
error: false,
};
this.entityData = value;
this.__internalSource.next(this);
}
load() { ... }
reload() { ... }
private requestData() { ... }
}
export class CollectionModel extends EntityModel {
@attr name: string;
}
export class ProductModel extends EntityModel {
@attr name: string;
@attr description: string;
@hasOne('collection') collection: CollectionModel;
}
While this setup somewhat works, it eventually encounters issues. For example, when using the following in Angular:
// component
export AppComponent {
product = new ProductModel('product', '1');
}
// The following works...
<div *ngIf="product | async as prod">
{{prod.loading}} works
{{prod.reloading}} works
{{prod.loaded}} works
{{prod.error}} works
{{prod.name}} works
{{prod.id}} works
{{prod.type}} works
</div>
// This doesn't work...
<div *ngIf="product | async as prod">
<div *ngIf="prod.collection | async as collection">
{{collection.loaded}} // TS throws an error that "Object is of type unknown"
</div>
<div *ngIf="prod.collection.loaded"> This works?
{{ prod.collection.name }} works
</div>
</div>
The reason behind this behavior eludes me.