Question

The issue is in the model, when recalled by the presenter it does not work like I assumed, in fact it works as if the this keyword refers to an [object HTMLTextAreaElement], not to a Model object.

/** PRESENTER **/

function Presenter() {
  var toolbarView;
  var outputView;
  var sourceCodeModel;
  var public = {
    setToolbarView: function (view) {
      toolbarView = view;
    },
    setOutputView: function (view) {
      outputView = view;
    },
    setModel: function (_model) {
      sourceCodeModel = _model;
    },
    init: function () {
      toolbarView.setNewTableHandler(function () {
        outputView.updateSource(sourceCodeModel.string);
      });
      toolbarView.setNewConstraintHandler(function () {
        /*stub*/
        alert("new constraint");
      });
    }
  }
  return public;
}
/** TOOLBAR VIEW **/
function toolbarView() {
  this.setNewTableHandler = function (handler) {
    $("#newTable").click(handler);
  }
  this.setNewConstraintHandler = function (handler) {
    $("#newConstraint").click(handler);
  }
}
/** OUTPUT VIEW **/
var outputView = {
  updateSource: function (newVal) {
    $("#sourcetext").val(newVal);
  },
  draw: function () {
    //stub
  }
};
/** MODEL **/
var model = new Object(); //o {};
model.source = [];
model.string = function () {
  /* ALERT(this) returns [object HTMLTextAreaElement] wtf? */
  var stringa = "";
  for (var i = 0; i < this.source.length; i++) { //this does not work, since this = HTMLTextAreaElement
    stringa += this.source[i] + "\n";
  }
  return stringa;
}
$(document).ready(function () {
  var presenter = new Presenter();
  var view1 = new toolbarView();
  presenter.setToolbarView(view1);
  presenter.setOutputView(outputView);
  presenter.setModel(model);
  presenter.init();
});

and the HTML is pretty simple:

<!doctype html>
<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script type="text/javascript" src="mvp.js"></script>
  <meta charset="UTF-8">
  <title>Titolo documento</title>
  <style type="text/css">
    /*unnecessary here*/
  </style>
</head>
<body>
  <div id="container">
    <div id="toolbar">
      <button id="newTable">New table</button>
      <button id="newConstraint">New Constraint</button>
    </div>
    <div id="source">
      <textarea id="sourcetext"></textarea>
    </div>
    <button id="update">Update</button>
    <div id="output"></div>
  </div>
</body>

</html>

What am i doing wrong on the model object?

Was it helpful?

Solution

When you pass a function as a listener the this property will not be available inside the function:

var obj = {
    a: function() {
        alert(this)
    }
};
$('body').click(obj.a);

When body is clicked the function's this property will be document.body.

To prevent this you must bind the function:

$('body').click(obj.a.bind(obj));

Or in older browsers wrap it:

$('body').click(function() {
    obj.a();
});

So you must bind the function before pass it:

outputView.updateSource(sourceCodeModel.string.bind(sourceCodeModel));

More info about javascript function's context: http://www.quirksmode.org/js/this.html

OTHER TIPS

this line: var public = { try to do not to use public, that is reserved word.

And a general note, try to bind this to a variable, because this changes context where it is currently.

/** TOOLBAR VIEW **/
function toolbarView() {
  var that = this; 
  that.setNewTableHandler = function (handler) {
    $("#newTable").click(handler);
  }
  that.setNewConstraintHandler = function (handler) {
    $("#newConstraint").click(handler);
  }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top