2010
01.17

Continuing with my current javascript theme i’ve been thinking quite a bit about the way in which we write RIAs. It would seem from many examples i’ve seen that it’s always approached like someones first windows forms application. All the code is in one file with a mixture of purposes and frequently very difficult to test. I’ve seen a few attempts to solve the problem but the intention/responsibility of the code is never quite clear.

After some experimentation the best way seems to be to adopt a MVP (Passive View) style approach. Here’s an example…

var CalculatorPresenter = {
  setup: function() {
    CalculatorView.setup();
  },
  addNumbers: function() {
    var firstNumber = CalulatorView.getFirstNumber();
    var secondNumber = CalculatorView.getSecondNumber();
    CalcualtorView.setResults(firstNumber + secondNumber);
  }
}

var CalculatorView = {
  setup: function() {
    $("addbutton").click(CalculatorPresenter.addNumbers);
  },
  getFirstNumber: function() {
    return parseInt($("firstnumber").val());
  },
  getSecondNumber: function() {
    return parseInt($("secondnumber").val());
  },
  setResult: function(value) {
    $("result").val(value);
  }    
};

$(document).ready(CalculatorPresenter.setup);

I really like this approach because the intention is not lost in a sea of UI code. Everything that relates to DOM manipulation or traversing should be in the view and the “logic” should be in the presenter. Testing this now becomes very simple, here’s an example using jsTestDriver to test the view…

CalculatorViewTest = TestCase("CalculatorViewTest", {
  testThatTheValueOfTheFirstFieldCanBeRetrieved: function() {
    $("body").append(
      $("<input/>")
        .attr("id","firstnumber")
        .attr("type","text")
        .attr("value","10"));
    assertEquals(10, CalculatorView.getFirstNumber());
  }
});

Same again but for the presenter, I’m also using the Jack mocking framework to isolate it from the view so i’m not testing both.

CalculatorPresenterTest = TestCase("CalculatorPresenterTest", {
  testAddingTwoNumbersTogether: function() {
    jack(function() {
      jack.expect("CalculatorView.getFirstNumber").returnValue(10);
      jack.expect("CalculatorView.getSecondNumber").returnValue(10);
      jack.expect("CalculatorView.setResult").stub().withArguments(20);
      CalculatorPresenter.addNumbers();
    });
  }
});

No Comment.

Add Your Comment