Created
July 29, 2019 11:22
-
-
Save adamauckland/868a1d0f227428a9f059d7eeac74b77a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The model returned from a web service | |
*/ | |
class VehicleModel { | |
public make: string; | |
public model: string; | |
public colour: string; | |
} | |
/** | |
* A place to store models to make the views faster | |
*/ | |
class VehicleCache { | |
protected static cache: Array<VehicleModel>; | |
public hasKey(id: string): boolean { | |
// return true if VehicleCache.cache has a vehicle with id | |
} | |
public set(vehicle: VehicleModel): void { | |
// put some logic here to stop duplicates | |
VehicleCache.cache.push(vehicle); | |
} | |
public get(id: string): VehicleModel { | |
return VehicleCache.cache.find(vehicle => vehicle.id === id); | |
} | |
} | |
/** | |
* The resource only handles web services, will be unit tested with mocks | |
*/ | |
class VehicleResource { | |
public get(id: string): Observable<VehicleModel> { | |
return new Observable((subscriber: Subscriber<VehicleModel>) => { | |
this | |
.httpClient | |
.get(`/vehicle/${id}`) | |
.subscribe((vehicle: VehicleModel) => { | |
subscriber.next(vehicle); | |
subscriber.unsubscribe(); | |
}, (error) => { | |
subscriber.error(error); | |
}); | |
}); | |
} | |
} | |
/** | |
* The repository handles pulling items out of the cache or web service | |
*/ | |
class VehicleRepository { | |
constructor( | |
private vehicleCache: VehicleCache, | |
private vehicleResource: VehicleResource, | |
) {} | |
public get(id: string): Observable<VehicleModel> { | |
return new Observable<VehicleModel>((subscriber: Subscriber<VehicleModel>) => { | |
if (this.vehicleCache.hasKey(id)) { | |
subscriber.next(this.vehicleCache.get(id)); | |
} | |
this | |
.vehicleResource | |
.get(id) | |
.subscribe((vehicleModel: VehicleModel) => { | |
this.vehicleCache.set(vehicleModel); | |
subscriber.next(vehicleModel); | |
subscriber.unsubscribe(); | |
}, (_error) => { | |
subscriber.error(_error); | |
}); | |
}); | |
} | |
} | |
/** | |
* metadata for the view | |
*/ | |
class ViewModelMeta { | |
public isNew: boolean; | |
} | |
/** | |
* ViewModels specific to each View, wrap the model so we can attach metadata for transitions without | |
* polluting the common model | |
*/ | |
class NewVehicleViewModel { | |
public meta: ViewModelMeta; | |
public vehicleModel: VehicleModel; | |
constructor() { | |
this.meta = new ViewModelMeta(); | |
} | |
} | |
/** | |
* The composition manager assembles everything the view will need. | |
*/ | |
class NewVehicleViewCompositionManager { | |
constructor( | |
private vehicleRepository: VehicleRepository, | |
) {} | |
public load(id: string): NewVehicleViewModel { | |
let newVehicleViewModel = new NewVehicleViewModel(); | |
newVehicleViewModel.meta.isNew = true; | |
newVehicleViewModel.vehicleModel = null; | |
this.vehicleRepository.get(id).subscribe((vehicleModel: VehicleModel) => { | |
newVehicleViewModel.vehicleModel = vehicleModel; | |
}); | |
} | |
} | |
/** | |
* The controller picks a composition manager to hydrate the viewmodel | |
*/ | |
class NewVehicleController implements OnInit, OnDestroy { | |
private loadDataSubscription: any; | |
protected viewModel: NewVehicleViewModel; | |
constructor( | |
protected newVehicleViewCompositionManager: NewVehicleViewCompositionManager, | |
protected pageRoute: ActivatedRoute, | |
) | |
public ngOnInit(): void { | |
const id = this.pageRoute.snapshot.params["id"]; | |
this.loadDataSubscription = this.newVehicleViewCompositionManager.load(id); | |
} | |
public ngOnDestroy(): void { | |
this.loadDataSubscription.unsubscribe(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
example