Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Spoilers!!
(duh..)

This code manipulates two HTML number input controls and multiplies them.

I am trying my luck on implementing MVC in JavaScript by example. This is a very minimal and useless code! What I am doing is achievable directly; by listening to the "change" or "input" event number-input fires. And here I am bloating code in order to learn. What a waste of time, ours, combined.

Anyway, here I am and here you are: gist | jsfiddle

function Event() {
  this.listeners = []
}

Event.prototype = {
  attach: function(listener) {
    this.listeners.push(listener)
  },
  notify: function(args) {
    this.listeners.forEach(function(l) {
      l(args)
    })
  }
}

function Model(numberValue, timesValue) {
  this.numberValue = numberValue
  this.timesValue = timesValue
  this.numberUpdated = new Event()
  this.timesUpdated = new Event()
  var self = this
  this.changeNumber = function(number) {
    self.numberValue = number
    self.numberUpdated.notify()
  }
  this.changeTimes = function(times) {
    self.timesValue = times
    self.timesUpdated.notify()
  }
  this.getNumber = function() {
    return self.numberValue
  }
  this.getTimes = function() {
    return self.timesValue
  }
}

function View(model, elements) {
  this.model = model
  this.elements = elements
  this.numberChanged = new Event()
  this.timesChanged = new Event()
  var self = this
  this.model.numberUpdated.attach(function() {
    self.recalculate()
  })
  this.model.timesUpdated.attach(function() {
    self.recalculate()
  })
  this.elements.number.addEventListener('input', function() {
    self.numberChanged.notify({
      value: self.elements.number.value
    })
  })
  this.elements.times.addEventListener('input', function() {
    self.timesChanged.notify({
      value: self.elements.times.value
    })
  })
  this.recalculate = function() {
    self.elements.result.innerHTML = self.model.getNumber() * self.model.getTimes()
  }
  this.show = function() {
    self.elements.number.value = self.model.getNumber()
    self.elements.times.value = self.model.getTimes()
    self.recalculate()
  }
}

function Controller(model, view) {
  this.model = model
  this.view = view
  var self = this
  this.view.numberChanged.attach(function() {
    self.model.changeNumber(self.view.elements.number.value)
  })
  this.view.timesChanged.attach(function() {
    self.model.changeTimes(self.view.elements.times.value)
  })
}

function run() {
  var number = document.getElementById('number')
  var times = document.getElementById('times')
  var result = document.getElementById('result')
  var model = new Model(9, 0.987654321)
  var elements = {
    number: number,
    times: times,
    result: result
  }
  var view = new View(model, elements)
  var controller = new Controller(model, view)
  view.show()
}

run()
#result,
input[type="number"] {
  padding: 4px;
  font-size: 16px;
  background-color: transparent;
  border: none;
  text-align: center;
  display: inline-block;
}
<div>
  Try changing the numbers. Use buttons. OR you know what, enter a number.
</div>

<input type="number" id="number" value="3">*
<input type="number" id="times" value="3">= <span id="result"></span>

As of right now, I am very happy that I got this working. It's an achievement for me. Really! And I know this code is bad, somehow; I cannot shake the feeling. (cue Max Payne music)

I knew it when I started writing code, I knew it in my gut that something was off; I was tired, I could have stopped, I didn't. I had to find out what will be wrong with the code.

What is this code missing? What makes it less of an MVC implementation?

share|improve this question
    
I think you went wrong having 1 model to rule them all, 1 view to rule them all and 1 controller to rule them all. What would be more logical is to have 2 instances of a NumberModel, 1 instance of a ResultModel. Each with their own view. The controller, would then handle changes of those models, and passing it on to "the business logic layer". This would be some code responsible for the "strategy" on how to achieve a result given the values of 2 NumberModels. In this case "multiply". – Pinoniq Jan 15 at 13:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.