wiki:NewModelProposal

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