Javascript "this" issue in Model View Presenter design - javascript

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?

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

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);
}
}

Related

Create "on" event listener on javascript custom object

How can I add on event listener for custom object.
For example:
(function () {
this.EmojiPicker = (function () {
function EmojiPicker(options) {
// ...
}
EmojiPicker.prototype.test = function () {
//...
};
return EmojiPicker;
})();
}).call(this);
I want to add
let emojiPicker = new EmojiPicker();
emojiPicker.on("change", function () {
//
});
I have a simple example modified from you code.
See if this can help.
The main idea is to trigger an event by $(emojiPicker).trigger('change');,
so that you can receive with $(emojiPicker).on("change", function () {});
<html>
<head>
<script type="text/javascript" src="./jquery-1.7.1.js"></script>
<script>
(function () {
this.EmojiPicker = (function () {
function EmojiPicker(options) {
// ...
}
EmojiPicker.prototype.test = function () {
//...
$(emojiPicker).trigger('change');
};
return EmojiPicker;
})();
let emojiPicker = new EmojiPicker();
$(emojiPicker).on("change", function () {
alert("triggered");
});
}).call(this);
</script>
</head>
<body>
</bofy>
</html>
More information from Custom events in jQuery?

Overriding functions in javascript is not working, debugger skips my code

I am trying to modify an application by overriding certain functions. I cannot release the code due to enterprise ownership. My code looks like this:
<html>
<head>
<script type="text/javascript" src="https://mylink.scriptX.js"></script>
// Some other scripts and css references
</head>
<body>
<script>
$(document).ready(function () {
form_script = my_script =
{
initialization:function (mode, json_data) {
this.parent_class.initialization(mode, json_data);
//Mycode to override the functions in scriptX.js is below:
var x= {};
function inherit(x) {
var y= {};
y.prototype = x;
return y;
};
(function ($) {
var OverrideFunctions = inherit($.my_methods);
OverrideFunctions.function1 = function () { ...};
OverrideFunctions.function2 = function () { ...};
OverrideFunctions.function3 = function () { ...}
})(jQuery);
}
//some original code here
}
</script>
//some other code here
</body>
</html>
Now the content of the scriptX.js is something like this:
(function ($) {
var my_methods = {
function1 = function () { ...};
function2 = function () { ...};
function3 = function () { ...}
}
})(jQuery);
The problem is that, I am noticing that the debugger skips the whole block of code since OverrideFunctions.function1 = function () { to the end })(jQuery);
So my functions are not being executed and thus the application is not changed. I was wondering if that could be related

Javascript return function

i want to create some javascript object with few functions, but i get a exception
undefined is not a function
JS:
var Buses = null;
$(function () {
Buses = function() {
return {
Test: function () {
console.log('test public function');
}
}
}
});
HTMl:
<button onclick="Buses.Test()">test</button>
<script type="text/javascript" src="js/buses.js" ></script>
What is wrong?
Your Buses variable is a function that returns a function so in the HTML it must be called like this
<button onclick="Buses().Test()">test</button>
While you are using jQuery, a better solution would be to give the button an and then assign the click handler right in the javascript:
var Buses = null;
$(function () {
Buses = function() {
return {
Test: function () {
alert('test public function');
}
}
}
$("#button").click(function() {Buses().Test()});
});
Here's the fiddle http://jsfiddle.net/fe5hxo60/

Cannot access js object methods from an event handler

This HTML snippet creates an Object prototype, instantiates it, then unsuccessfully tries to use that object's methods from an Event.
<body>
<button type="button" onclick="TestLogic()">Test Logic</button>
<script>
function onOff() //Object prototype
{
this.state = false;
function setState(newState) {
this.state = newState;
}
}
var inputOne = new onOff(); //Instantiate object prototype
function TestLogic() //buttonClick Event Handler
{
inputOne.setState(true);
// generates Uncaught Type Error undefined is not a function */
document.inputOne.setState(true);
// generates Uncaught Type Error Cannot read property setState of undefined
}
</script>
</body>
The function in onOff is private, it's not being published as a public property. Change function setState(newState) { ... } to this.setState = function(newState) { ... }.
You have misunderstanding about javascript contexts. MDN has good article about it. See comments to know where you was wrong:
<body>
<button type="button" onclick="TestLogic()">Test Logic</button>
<script>
function onOff() //Object prototype
{
this.state = false;
//set method to context of creating Object
this.setState = function (newState) {
this.state = newState;
}
}
var inputOne = new onOff(); //Instantiate object prototype
function TestLogic() //buttonClick Event Handler
{
inputOne.setState(true);
//document is not a scope, window is global scope
window.inputOne.setState(true);
}
</script>
</body>
Try this
<html>
<body>
<button type="button" onclick="TestLogic()">Test Logic</button>
<script>
function onOff() //Object prototype
{
this.state = false;
this.setState=function(newState)
{
this.state = newState;
console.log(this.state);
}
}
var inputOne = new onOff();
function TestLogic()
{
inputOne.setState(true);
}
</script>
</body>
</html>
If you want to use prototypes then use prototypes like this
function Object () {
this.instanceMethod = false;
}
Object.prototype.prototypeMethod = function () {};
Also you should avoid using inline event listeners and do it like this instead
document.querySelector('button').addEventListener('click', function () {
// logic
});
And here is an example of it all used together (http://jsfiddle.net/sAH35/)
<body>
<button type="button">Test Logic 1</button>
<button type="button">Test Logic 2</button>
<button type="button">Test Logic 3</button>
<script>
//Object prototype
function OnOff(element) {
this.element = element;
this.state = false;
}
OnOff.prototype.setState = function (newState) {
this.state = newState;
if (this.state) {
this.element.style.backgroundColor = 'red';
} else {
this.element.style.backgroundColor = 'grey';
}
};
// bind to elements
var elements = document.querySelectorAll('button');
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', function () {
if (!this.onOff) this.onOff = new OnOff(this);
this.onOff.setState(!this.onOff.state);
});
}
</script>
</body>

Unable to target a selector using Namespace ,Modular, Private

i am trying to target a jquery selector by using namespaces in my script and also making function private but i think i am still missing something here, can anyone guide. It works if i try by adding a breakpoint on the last line and than use devtools to access MyUtility.Selectors.ColorCss.myBorder()
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Selectors</title>
</head>
<body>
<ul>
<li class="test">First</li>
<li>Second</li>
<li>Third</li>
</ul>
<!--<script>
$('document').ready(function(){
$('li.test').css('color','green')
})
</script>-->
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script>
var customModule = (function () {
var MyUtility = {
Selectors: {
ColorCss: function () {
var myBorder = function () {
$('li').css('color', 'red')
console.log('hello')
}
return{
myBorder: myBorder
}
}()
}
}
}())
</script>
</body>
</html>
As you said It works if i try by adding a breakpoint on the last line and than use devtools to access MyUtility.Selectors.ColorCss.myBorder()
This is your code:
var customModule = (function () {
var MyUtility = {
Selectors: {
ColorCss: function(){
var myBorder = function(){
$('li').css('color', 'red');
console.log('hello');
}
return{ myBorder: myBorder }
}()
} // Selectors
} // MyUtility
}())
Your code above can be written as:
function myBorderFunc() { $('li').css('color', 'red'); console.log('hello');}
var selectorObj = { ColorCss : function(){ return{ myBorder: myBorderFunc } }()};
var MyUtility = { Selectors: selectorObj};
var customModule = ( function(){ MyUtility }() );
This shows the problem
var customModule is a function expression that does not return anything and it is therefore undefined
since customModule is undefined you can not use customModule.MyUtility
as you said you can call MyUtility.Selectors.ColorCss.myBorder() since MyUtility is an object that has a property Selectors and so on
you can test it out with this example:
// undefined since nothing is returned
var bar = (function(){ {Foo: "i am foo"} }());
// returns foo and can be used bar.Foo ---> "i am foo"
var bar = (function(){ return {Foo: "i am foo"} }());
To 'fix your code' return MyUtility
var customModule = (function () {
var MyUtility = {
Selectors: {
ColorCss: function(){
var myBorder = function(){
$('li').css('color', 'red');
console.log('hello');
}
return{ myBorder: myBorder }
}()
} // Selectors
} // MyUtility
return MyUtility;
}())
This way you can access it like this customModule.Selectors.ColorCss.myBorder().
More info about Function expressions vs. Function declarations

Categories

Resources