Here's an example calculator code that demonstrates the ideas behind my new MVC API proposal.
The main classes are Record and Forwarder. Record is already in svn; it can optionally invoke callbacks on a list of registered observers when the value of an observed field changes. Forwarder would be a class that forwards methods to a delegate, effectively acting as a "method translator". Forwarder would recognize special target method prefixes and generate setters ("+"), getters("-") or updaters("!") accordingly.
Here's the calculator example. It's complete except for the definitions of InputBox?, OutputBox?, Forwarder, and Record. I use the term "formals" to denote a View's terminology regarding model variables, and "actuals" to denote the variable names of the actual model instance hooked up to views.
var CalcModel = Record.create({
Op1: {}
Op2: {}
Result: {}
}); // CalcModel is a constructor
var m = new CalcModel(backingStore, {Op1: 10, Op2: 20, Result: 0});
// backingStore could be the DOM, SQL or plain JavaScript
// the particular view that will operate on the calc. Note that it could be replaced by, say a Multiplier, and neither CalcModel, nor OutputBox and InputBox sould notice.
function Summator() {}
// this is domain logic
Summator.prototype = {
firstSummandChanged: function(value) { this.formalModel.setSum(value + this.formalModel.getSummand2()); },
secondSummandChanged: function(value) { this.formalModel.setSum(this.formalModel.getSummand1() + value); },
};
var summator = new Summator();
// summator writes a to its model m a formal "Sum", which maps to m's "Result" and reads "Summand1" and "Summand2", which map to m's "Op1" and "Op2" respectively.
summator.formalModel = new Forwarder.create({ Sum: "+Result", Summand1: "-Op1", Summand2: "-Op2"})(m);
// note that Forwarder.create() creates a constructor, which is subsequently called on m.
// model will call onOp1Update or onOp2Update on the forwarder
// the forwarder will forward onOp1Update to summator.firstSummandChanged, and onOp2Update to summator.secondSummandChanged
m.addObserver(new Forwarder.create({ Op1: "!firstSummandChanged", Op2: "!secondSummandChanged" })(summator), ["Op1", "Op2"]); // sidenote: second argument to addObserver() is not strictly necessary
var op1Box = new InputBox(); // a UI control
// formalModel will forward setInput() to m.setOp1()
op1Box.formalModel = new Forwarder.create({Input: "+Op1"})(m);
// when editing is done, InputBox sets its formal "Input" variable which will result on m.setOp1() being called
var op2Box = new InputBox(); // another UI control for input
op2Box.formalModel = new Forwarder.create({Input: "+Op2"})(m);
var resBox = new OutputBox(); // another UI control
// m will call resBox.display() whenever m.Result is set
m.addObserver(new Forwarder.create({Result: "!display" })(resBox), "Result");
Note that both Record and Forwarder would be reusable, and not strictly tied to the MVC model.
Jens and Robert drew a diagram to better understand the actors and the control flow.
Attachments
-
newModel2.png
(71.2 KB) -
added by robertkrahn 3 years ago.

