Skip to content

Instantly share code, notes, and snippets.

@yreynhout
Created August 5, 2012 11:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yreynhout/3264054 to your computer and use it in GitHub Desktop.
Save yreynhout/3264054 to your computer and use it in GitHub Desktop.
Viewmodels - Sample 5
var ThingDetailViewModel = function() {
if (!this instanceof ThingDetailViewModel) {
return new ThingDetailViewModel();
}
var self = this,
states = { none: 0, adding: 1, modifying: 2},
statemachine = new SimpleStatemachine(states.none),
baseData = null,
buildCommand;
self.Name=new TextInput();
//more inputs go here ...
self.Save=new Trigger();
self.Cancel=new Trigger();
// Example of viewmodel self-contained behavior,
// i.e. not every behavior needs to relay to the controller.
self.Cancel.setCallback(function() {
if(statemachine.isState(states.adding)) {
//clear and disable inputs
self.Name.clear();
self.Name.disable();
self.Save.disable();
self.Cancel.disable();
} else if(statemachine.isState(states.modifying)) {
//reset inputs
self.Name.setValue(baseData.Name);
}
});
// Explicit installment of the controller into the viewmodel
self.installController = function(controller) {
ns.guard.notnull({ controller: controller });
ns.guard.hasmethods(controller, ['saveThing']);
// bind any callbacks to the controller
self.Save.setCallback(function() {
controller.saveThing(baseData.Id);
});
};
// Called by the controller with an empty data skeleton
self.addThing = function(data) {
ns.guard.notnull({data:data});
statemachine.transitionTo(states.adding);
baseData = data;
self.Name.setValue(data.Name);
self.Name.enable();
self.Save.enable();
self.Cancel.enable();
self.Name.focus();
};
// Called by the controller with data gotten from the server
self.modifyThing = function(data) {
ns.guard.notnull({data:data});
statemachine.transitionTo(states.modifying);
baseData = data;
self.Name.setValue(data.Name);
self.Name.enable();
self.Save.enable();
self.Cancel.enable();
self.Name.unfocus();
};
// Called by the controller to know if something was changed,
// which gets delegated to its composed parts
self.hasChanges=function() {
if(statemachine.isState(states.none)) return false;
if(statemachine.isState(states.adding)) return true;
return self.Name.isChanged();
};
// Called by the controller to fetch the changes that should be
// sent to the server (command, request, data, whatever floats your boat)
self.getChanges=function() {
if(!self.hasChanges()) {
return [];
}
return [buildCommand()];
};
// Called by the controller to indicate changes are not longer pending
self.acceptChanges=function() {
self.Name.acceptChange();
};
buildCommand=function() {
//Oh no's we're in CQRS land here ...
};
// Called by the controller to see if the model is valid,
// where this is the simplest of examples.
self.validate = function() {
return self.Name.validate();
};
//more behavior goes here ...
};
var ThingController = function(queryApi, commandBus, dialogService) {
if (!this instanceof ThingController) {
return new ThingController(queryApi, commandBus, dialogService);
}
var self = this,
viewModel = null,
listItemFactory = new ThingListItemViewModelFactory(self),
...;
// Example of binding the view model to the controller,
// which could be done in many ways.
self.init=function(thingViewModel) {
viewModel=thingViewModel;
viewModel.installController(self);
};
// Example of flow and coordination activity
self.saveThing = function(idOfThingToSave) {
if(viewModel.hasChanges()) {
if(viewModel.validate()) {
commandBus.sendBatch(viewModel.getChanges(), {
success: function() {
viewModel.acceptChanges();
},
failure: function(error) {
dialogService.showError(error);
}
});
}
}
};
// many more methods go here ...
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment