JavaScript MVC Example (jQuery)

by Artem

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<div class="row container">
  <div class="col-xs-4">
    <select id="list" class="form-control" size="10"></select>
  </div>
  <div class="col-xs-8">
    <button id="plusBtn" class="btn btn-default btn-block">+</button>
    <button id="minusBtn" class="btn btn-default btn-block">-</button>
  </div>
</div>

CSS

.row {
  padding-top: 10px;
}

.btn {
  width: 5em;
}

JavaScript

function Event(sender) {
  this._sender = sender;
  this._listeners = [];
}

Event.prototype = {
  attach: function(listener) {
    this._listeners.push(listener);
  },
  notify: function(args) {
    var index;

    for (index = 0; index < this._listeners.length; index += 1) {
      this._listeners[index](this._sender, args);
    }
  }
};

/**
 * The Model. Model stores items and notifies
 * observers about changes.
 */
function ListModel(items) {
  this._items = items;
  this._selectedIndex = -1;

  this.itemAdded = new Event(this);
  this.itemRemoved = new Event(this);
  this.selectedIndexChanged = new Event(this);
}

ListModel.prototype = {
  getItems: function() {
    return [].concat(this._items);
  },

  addItem: function(item) {
    this._items.push(item);
    this.itemAdded.notify({
      item: item
    });
  },

  removeItemAt: function(index) {
    var item;

    item = this._items[index];
    this._items.splice(index, 1);
    this.itemRemoved.notify({
      item: item
    });
    if (index === this._selectedIndex) {
      this.setSelectedIndex(-1);
    }
  },

  getSelectedIndex: function() {
    return this._selectedIndex;
  },

  setSelectedIndex: function(index) {
    var previousIndex;

    previousIndex = this._selectedIndex;
    this._selectedIndex = index;
    this.selectedIndexChanged.notify({
      previous: previousIndex
    });
  }
};

/**
 * The View. View presents the model and provides
 * the UI events. The controller is attached to these
 * events to handle the user interraction.
 */
function ListView(model, elements) {
  this._model = model;
  this._elements = elements;

  this.listModified = new Event(this);
  this.addButtonClicked = new Event(this);
  this.delButtonClicked = new Event(this);

  var _this = this;

  // attach model listeners
  this._model.itemAdded.attach(function() {
    _this.rebuildList();
  });
  this._model.itemRemoved.attach(function() {
    _this.rebuildList();
  });

  // attach listeners to HTML controls
 ...