How to call "class method" from outside class in JavaScript? - javascript

I've got some code in JavaScript and I'm looking to trigger a ViewModel method using a keyboard shortcut. What is the correct syntax? Here's my code:
document.addEventListener('keydown', function(event) {
if (event.keyCode==27){
ViewModel.escapePressed();
}
}, true);
function ViewModel() {
this.escapePressed=function(){
// Code
};
}

If you are going to use that style of class, then you must first make an instance of it.
var a_view_model = new ViewModel();
a_view_model.escapePressed();
… but if you just want to have a static method, then you probably shouldn't be using a constructor function in the first place
var view_model = {
escapePressed: function () { };
}
and:
view_mode.escapePressed();

Related

javascript namespace call other function methods

I try to change some way to call methods into namespace.
Calling parent methods (I dont think its possible)
Creating and call inheritance function
Calling inside another method (mostly jquery onReady event function) (this.MyFunction() not working)
I split every namespace in files (want to keep it that way)
I try How to call function A from function B within the same namespace? but I didn't succed to split namespaces.
my fiddle sample got only 1 sub-namespace but could be more.
https://jsfiddle.net/forX/kv1w2rvc/
/**************************************************************************
// FILE Master.js
***************************************************************************/
if (!Master) var Master = {};
Master.Print= function(text){
console.log("master.Print :" + text);
$("body").append("<div>master.Print : " + text + "</div>");
}
/**************************************************************************
// FILE Master.Test1.js
***************************************************************************/
if (!Master) var Master = {};
if (!Master.Test1) Master.Test1 = {};
/**************************************************************************
* Descrition :
* Function for managing event load/documentReady
**************************************************************************/
Master.Test1.onReady = function () {
$(function () {
Master.Test1.Function1(); //try to replace because need all namespace.
try {
this.Function2(); //not working
}
catch(err) {
console.log("this.Function2 not working");
$("body").append("<div>this.Function2 not working</div>");
}
try {
this.Print("onReady"); //not working
}
catch(err) {
console.log("this.Print not working");
$("body").append("<div>this.Print not working</div>");
}
try {
Print("onReady"); //not working
}
catch(err) {
console.log("Print not working");
$("body").append("<div>Print not working</div>");
}
});
}
Master.Test1.Function1 = function () {
console.log("Function1");
$("body").append("<div>Function1</div>");
this.Function3(); //working because not inside another function
}
Master.Test1.Function2 = function () {
$("body").append("<div>Function2</div>");
console.log("Function2");
}
Master.Test1.Function3 = function () {
$("body").append("<div>Function3</div>");
console.log("Function3");
Master.Print("Function3"); //try to replace because need all namespace.
}
Master.Test1.onReady();
I use Master.Test1.Function1(); and I want to change that because Function1 is inside the same namespace.
I use Master.Print("Function3"); I dont think I can change that. the way I try to use it, it's more an inheritance function. but I dont know if theres a way to do that?
Maybe I should change the my namespace methode? maybe prototype will do what I want?
You can capture the this in a variable because this inside $(function() {}) will point to document object. The below will work provided you never change the calling context of onReady -- i.e. it is always called on the Test1 object and not called on other context:
Master.Test1.onReady = function () {
var self = this;
$(function () {
self.Function1();
// ..
});
}
To access Print you have to reference using the Master object like: Master.Print() as it won't be available in the Test1 object
this is document within .ready() or jQuery() alias for .ready() where function(){} is parameter $(function() {}). this at this.Function2() will reference document.
"Objects" in javascript are not built the same way as in most object-oriented languages. Essentially, what you are building is a hierarchy of static methods that have no real internal state in-and-of themselves. Therefore, when one of the defined methods is invoked, the context (or state) of that method depends on what object invoked the method.
If you want to have any internal context, you will need to create an "instance" of an "object prototype". At that point, you can use "this.otherFunction" within your other functions. Here is a small example:
var MyObject = function() {};
MyObject.functionOne = function() {
console.log("Function 1");
this.functionTwo();
};
MyObject.functionTwo = function() {
console.log("Function 2");
};
var instanceOne = new MyObject();
instanceOne.functionOne();
You might get some more information about object definition here

JavaScript: TypeError: xyz is not a function when calling the function

I am trying to come up with a page on which, when user clicks a file button on the page, I try to execute the JS on the page. And I am trying to use OOP / class so hopefully it can be reused later. Here is my test code:
// This is the "class".
function BearUpload() {
// some values will go here...
}
// Add a few functions
BearUpload.prototype.function1 = function () {
console.log("function1 called");
}
BearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
var myBear = new BearUpload(); // Create a global variable for the test
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(myBear.handleFileSelect);
}
});
However, it gets error like:
TypeError: this.function1 is not a function
this.function1();
Any idea about this?
Thanks!
Bind myBear to your change eventListener
In general when you access this from handleFileSelect, this refers to the html element.
i.e. this = <input type="file" id="my-file-select-button">
$("#my-file-select-button").change(myBear.handleFileSelect.bind(myBear));
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
MDN doc
You are trying to call function1 on DOM object but you have to call on jQuery object
$(this).function1();
That's because when bound as a handler to jQuery events, this would refer to the element on which the event is triggered.
I would rather change your code like this
// Create only one global variable for your app
var APP = {};
// Create class using immediate function/closure
APP.BearUpload = (function(){
//declare private variables here
// Constructor
var bearUpload = function() {
// some values will go here...
}
// Add a few functions
bearUpload.prototype.function1 = function () {
console.log("function1 called");
}
bearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
return bearUpload;
}());
APP.myBear = new APP.BearUpload();
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(function(e){
// do something with event 'e'
APP.myBear.handleFileSelect.call(APP.myBear, e);
});
}
});
do not use "this", it is confusing some time.
BearUpload.prototype ={
function1:function(){
var self = this;
...
},
handleFileSelect:function(e){
var self = this;
...
}
}

Substitute Javascript this to Typescript

Recently I decided to convert my code into typescript, which lead to an issue of substituting this from JavaScript to TypeScript.
here is the code I am struggling with.
TypeScript:
/// <reference path="../typings/tsd.d.ts" />
class FormAjaxSubmit {
form:JQuery;
opt:any;
constructor(element:string) {
this.form = $(element);
this.opt = {
boxID : "#info",
invData: {
tag : "[data-invalid]",
tagTrue: "[data-invalid='true']"
},
msg : {
success: "",
field : ""
}
};
// Even Listeners
this.form
.on('focusout', "[data-invalid]", e => {
console.log(this); // outputs form.ajax object instead of current field with data-invalid
this.formVisuals(); // this method needs to be accessible too along with function's this
e.preventDefault();
});
}
private formVisuals() {
}
}
$(() => {
// Finally, we kick things off by creating the **App**.
new FormAjaxSubmit("form.ajax");
});
I understand why it happens as this is assigned to main class by typescript. So it simply creates var _this = this on the top level and continues using throughout the code which prevents me from using old JavaScript style like following:
$("form.ajax").on("focusout", [data-invalid], function(e) {
console.log(this) // it outputs the current field with data-invalid tag instead of the form object itself.
e.preventDefault();
}
So the question is is the a way to substitute JavaScript this in typescript.
Function expressions exist in TypeScript too. They're not "old JavaScript style".
this.form.on("focusout", "[data-invalid]", function(e) {
console.log(this); // works
e.preventDefault();
});
Basically, don't use arrow functions in these cases.
If you want to use both the class and the element, then you could do this:
this.form.on("focusout", "[data-invalid]", (e) => {
this; // class
e.target; // element
});
Or if you want to keep using this as the element instead of the class you could do this:
let self = this;
this.form.on("focusout", "[data-invalid]", function(e) {
self; // class
this; // element
});
I would recommend keeping this as the class though and use an arrow method... it reduces confusion by keeping the meaning of this consistent.

How to override a method in Object Oriented Javascript?

I was trying to implement an interface like architecture in JS as followed in C#. And met with a stumbling block. Here is the code sample:
// Interface for UIBuilder classes
function IUIBuilder() {
this.addUserToList = function () {
alert('parent: added');
};
}
// Class implementing the IUIBuilder
function ChatUIBuider() {
IUIBuilder.prototype.addUserToList = function () {
alert('child: added');
};
IUIBuilder.prototype.removeUserFromList = function () {
alert('child: removed');
};
return new IUIBuilder();
}
In the first class, I've defined a method addUserToList which I override in the second class ChatUIBuider. Also added one more method removeUserFromList to the base class using its prototype.
My issue is, the addUserToList method still invokes the parent class method even after it has got overridden in the child class. Why?
var builder = new ChatUIBuider();
builder.removeUserFromList(); // Invokes the child class method. - CORRECT
builder.addUserToList(); // Invokes the base class method- WHY??
Could anyone tell me if this is the correct way I am doing?
I suggest this construct :
function IUIBuilder() {
};
IUIBuilder.prototype.addUserToList = function () {
alert('parent: added');
};
// Class extending the IUIBuilder
function ChatUIBuider() {
}
ChatUIBuider.prototype = new IUIBuilder();
ChatUIBuider.prototype.addUserToList = function () {
alert('child: added');
};
ChatUIBuider.prototype.removeUserFromList = function () {
alert('child: removed');
};
ChatUIBuider extends IUIBuilder and inherits its functions but overrides the addUserToList function.
In the following code, both constructors will be called but only the overriding addUserToList function will be called :
var chat = new ChatUIBuider();
chat.addUserToList();
See demonstration
#Denys restructured the entire code , without exactly pointing out the issue. issue is addUserToList is not a prototype method of your parent class , it's a this method which is copied for every instance and not sahred. So just converting it to a prototype method fixes the issue.
// Interface for UIBuilder classes
function IUIBuilder() {
}
IUIBuilder.prototype.addUserToList = function () {
alert('parent: added');
};
// Class implementing the IUIBuilder
function ChatUIBuider() {
IUIBuilder.prototype.addUserToList = function () {
alert('child: added');
};
IUIBuilder.prototype.removeUserFromList = function () {
alert('child: removed');
};
return new IUIBuilder();
}
var builder = new ChatUIBuider();
builder.removeUserFromList(); // Invokes the child class method. - CORRECT
builder.addUserToList(); // Invokes the CHILD CLASS's METHOD

JavaScript: How to bind a method?

JSFiddle: http://jsfiddle.net/M2ALY/3/
My goal is to make a module that I can use and distribute. Therefore I must not pollute the global namespace. The module I'm making is also going to be used multiple times on one web page. That's why I chose to use OOP, but this introduced a problem.
I want my object to bind a function to be run when the user clicks an element in the DOM. In this simplified example I made, I want an alert box to pop up when the user clicks a paragraph. As an example, one of the things I need in the real project I'm working on is: The user clicks a canvas, the function figures out where the user clicked and saves it to this.clientX and this.clientY.
Instead of doing
this.bind = function() {
$("p1").bind('click', function() {
// code here
});
}
I figured it would work if I did:
this.bind = function() {obj.codeMovedToThisMethod()}
The problem is that this isn't a good design. Inside the "class" you shouldn't need to know the name of the object(s) that is going to be made of this "class". This doesn't get better when I'm making multiple objects of the "class"...
So I figured I could do
$("p1").bind('click', function(this) {
// code here
});
}
But it didn't work because sending this into the function didn't work as I thought.
How should I solve this problem?
Here is a simplified sample problem. (Same as JSFiddle.)
var test = function() {
this.alert = function() {
alert("Hi");
}
this.bind = function() {
$("#p1").bind('click', function() {
obj.alert();
});
}
}
window.obj = new test();
obj.bind();
// What if I want to do this:
var test2 = function() {
// Private vars
this.variable = "This secret is hidden.";
this.alert = function() {
alert(this.variable);
}
this.bind = function() {
$("#p2").bind('click', function(this) {
obj2.alert();
this.alert();
});
}
}
window.obj2 = new test2();
obj2.bind();​
Thanks!
Read MDN's introduction to the this keyword. As it's a keyword, you can't use it as a parameter name.
Use either
this.bind = function() {
var that = this;
$("#p2").on('click', function(e) {
that.alert();
// "this" is the DOM element (event target)
});
}
or $.proxy, the jQuery cross-browser equivalent to the bind() function:
this.bind = function() {
$("#p2").on('click', $.proxy(function(e) {
this.alert();
}, this));
}

Categories