When you say OOP principles, I'm assuming you are referring to SOLID.
View Models model the UI and do not have to be coupled to a single template. You may use a view model with a template that has been created to target desktops and then reuse that view model with a template that has been created to target mobiles.
Should my object model be ItemVM<-ShoeVM,ClothesVM,FurntitureVM as per
OOP rules, or should it be ParentVM containing ItemSelectorVM (for the
UI to select the item type), shoeAdverisementVM (to bind to the shoe
template loaded as a result), FurnitureAdvertisementVM and many more
VMs for every part of the page?
This depends on the complexity of the application and domain.
Let's assume that your UI is doing more than just iterating over an ObservableArray<T>
where T
could be of type Shoe
or Furniture
. And let's also assume that ShoeAdvertisementVM
is not some decorator of ItemVM<T>
.
Now, lets say you have FurnitureAdvertisementVM
and ShoeAdverisementVM
that look like this:
function FurnitureAdvertisementVM(furniture){
this.items = ko.observableArray(furniture);
this.doSomething = function(){
// doing something
}
}
function ShoeAdverisementVM(shoes){
this.items = ko.observableArray(shoes);
this.doSomething = function(){
// doing something
}
}
var shoeVM = new ShoeAdverisementVM(shoes);
var furnitureVM = new FurnitureAdverisementVM(furniture);
If the two view models are pretty much a copy and paste job and the only difference is the name of the view model and the type of the items that go into the collection then it's probably worth changing the implementation into something generic like this:
function ItemsVM(items){
this.items = ko.observableArray(items);
this.doSomething = function(){
// doing something
}
}
var shoeVM = new ItemsM(shoes);
var furnitureVM = new ItemsVM(furniture);
But if each view model has some very specific properties and functions, for example:
function FurnitureAdvertisementVM(furniture, someOtherDependency){
this.items = ko.observableArray(furniture);
this.doSomething = function(){
// doing something
}
this.propertyIsBoundToATextbox = ko.observable();
this.clickHandlerUsesDependency = function(ctx){
if(ctx.SomeCondition){
someOtherDependency.doSomething();
}
}
}
function ShoeAdverisementVM(shoes){
this.items = ko.observableArray(shoes);
this.doSomething = function(){
// doing something
}
this.propertyIsBoundToACheckbox = ko.observable();
}
Then it it is not as clear cut as making both view models generic.
Roy J commented:
your viewmodels are intended to model the view (the UI)
Which is so true, so if the views have different requirements, i.e. one has 3 checkboxes the other has loads of buttons etc, then you are likely going to need different view models.
If you want to factor out some of common functionality into separate classes then you can:
function ItemService(items){
this.items = ko.observableArray(items);
this.doSomething = function(){
// doing something
}
}
function FurnitureAdvertisementVM(itemService, someOtherDependency){
this.service = itemService;
this.propertyIsBoundToATextbox = ko.observable();
this.clickHandlerUsesDependency = function(ctx){
if(ctx.SomeCondition){
someOtherDependency.doSomething();
}
}
}
function ShoeAdverisementVM(itemService){
this.service = itemService;
this.propertyIsBoundToACheckbox = ko.observable();
}