how do I call sibling functions in a singleton class? - javascript

In the following code, .refresh could call .add, but I get Uncaught TypeError: undefined is not a function
My guess is because it is not defined at the time class is created, but if this is true, without replicating the code, is there a way to call a sibling public function from the same class?
var fileSelector = (function () {
var self = this;
function callback (data,status,xhr) {
$("#File_Selector_Container").html(data);
utils.setItem ("fileSelector", "TRUE");
}
return {
refresh : function () {
if (utils.getItem ("fileSelector") == "TRUE") {
self.add();
}
},
add : function () {
$.get(script_name ,"AddFileSelector",callback,"html");
},
remove : function () {
$("#File_Selector_Container").html("");
}
}
})();
I started this from: Simplest/Cleanest way to implement singleton in JavaScript? and I can't find it now, but another question where I got self=this from.

this (and hence self) simply refers to the global object (i.e. window). That's why you get the error, there is no global add function. I recommend to read the MDN documentation to learn how this works.
One solution is to keep a reference to the object you are returning and use that instead:
var fileSelector = (function () {
function callback (data,status,xhr) {
$("#File_Selector_Container").html(data);
utils.setItem ("fileSelector", "TRUE");
}
var fileSelector = {
refresh : function () {
if (utils.getItem ("fileSelector") == "TRUE") {
fileSelector.add();
}
},
add : function () {
$.get(script_name ,"AddFileSelector",callback,"html");
},
remove : function () {
$("#File_Selector_Container").html("");
}
};
return fileSelector;
})();

Related

Calling a function within a function inside an object literal [duplicate]

This question already has answers here:
How does the "this" keyword work, and when should it be used?
(22 answers)
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
So I'm doing a tutorial on one of the videos I found online. In that tutorial, he used IIFE to create mvc model rather than object literals.
I decided to recreate the project using object literals
This is the problem that I am having right now and I'm not sure what the problem is. I suspect it has something to do with scoping problem.
This is the code for the controller and at the end I initiate the init().
var model ={ //Code }
var view = {//Code}
var controller = {
dom: view.getDom(),
setEventHandler: function(){
document.addEventListener("keypress", function(ev){
if(ev.keyCode === 13){
this.addItem();
}
});
},
addItem: function(){
this.updateMethod();
// Code
},
init: function(){
this.setupEventHandler();
},
updateMethod: function(){
// Some code
}
{
controller.init();
Now when I press the enter key to invoke the event, i get an error from the console. It states:
"Uncaught TypeError: this.addItem is not a function at HTMLDocument.[anonymous]"
Question:
Why is it not recognizing the addItem()?
The same error message occurs within addItem() when I try to invoke this.updateMethod() too.
One way I found to have this.addItem() to get invoked in the event listener is by using () => rather than using a regular anonymous function declaration.
document.addEventListener("keypress", (ev) => {
if(ev.keyCode === 13){
this.addItem();
{
});
In JavaScript, the value of this is determined by how function is called. In your example, this refers to element on which event is bound.
There are few of ways,
Using Function#bind
Using Arrow Function
Keeping this in variable
Using Function#bind
var model = {};
var view = {};
var controller = {
dom: view.getDom(),
setEventHandler: function() {
document.addEventListener("keypress", function(ev) {
if (ev.keyCode === 13) {
this.addItem();
}
}.bind(this));
},
addItem: function() {
this.updateMethod();
// Code
},
init: function() {
this.setupEventHandler();
},
updateMethod: function() {
// Some code
}
};
controller.init();
Using Arrow Function:
var model = {};
var view = {};
var controller = {
dom: view.getDom(),
setEventHandler: function() {
document.addEventListener("keypress", (ev) => {
if (ev.keyCode === 13) {
this.addItem();
}
});
},
addItem: function() {
this.updateMethod();
// Code
},
init: function() {
this.setupEventHandler();
},
updateMethod: function() {
// Some code
}
};
controller.init();
Using variable holding this context
var model = {};
var view = {};
var controller = {
dom: view.getDom(),
setEventHandler: function() {
var _this = this;
document.addEventListener("keypress", function(ev) {
if (ev.keyCode === 13) {
_this.addItem();
}
});
},
addItem: function() {
this.updateMethod();
// Code
},
init: function() {
this.setupEventHandler();
},
updateMethod: function() {
// Some code
}
};
controller.init();
Question: Why is it not recognizing the addItem()?
...
One way I found to have this.addItem() to get invoked in the event listener is by using () => rather than using a regular anonymous function declaration.
Because with traditional function syntax, the value of this is bound by the caller, so it becomes the bound element. Whereas an arrow function does not bind its own this value, it will use the this from the setEventHandler method, which will be a reference to controller.
Be aware that init calls setupEventHandler but it should be setEventHandler.

Intercept a function in javascript

Following is my javaScript code.
var myObjfn = {
before : function(){
console.log("before");
},
loadA: function(){
console.log("loadA");
},
loadB: function(){
console.log("loadB");
},
loadC: function(){
console.log("loadC");
}
}
Whenever I call myObjfn.loadA(), it should call myObjfn.before() method before executing loadA method. Same for loadB() & loadC(). I don't want to explicitly call before() method in all loadA,loadB and loadC methods. Is there any option to achive this in javascript ?
You could do something like this. Which creates a wrapper function for each function in the object except the before function.
var myObjfn = { ... };
Object.keys(myObjfn).forEach(key => {
if (key === "before") return;
var oldFunc = myObjfn[key];
myObjfn[key] = function() {
myObjfn.before();
return oldFunc.apply(this, arguments);
};
});
myObjfn.loadA();
// "before"
// "loadA"

Defining methods

What does the method incorrect not work?
var myFunction = {}
myFunction.init = function() {
myFunction.correct = function() {
}
function incorrect() {
}
}
myFunction.init()
myFunction.correct()
myFunction.incorrect() // This doesn't work
'incorrect' is not a method of myFunction, only a function within myFunction's 'init' method.
'correct' has been set as a property/method, which is why it works and 'incorrect' does not.

How do I call a nested JavaScript function properly

I'm trying to set up function a nested function that I can call throughout my script, but I keep getting "error undefined is not a function". Perhaps someone can help me with how to do this correctly.
First I set global my variables:
var trigger = document.getElementById('trigger');
var subject = document.getElementById('subject');
Then I create a show/hide function:
var toggleVis = function() {
function showSomething() {
trigger.classList.add("active");
subject.classList.add("active");
}
function hideSomething() {
trigger.classList.remove("active");;
subject.classList.remove("active");
}
}
Then I set my event listener:
trigger.addEventListener('click', function() {
if ( subject.classList.contains("active") ) {
toggleVis.hideSomething();
}
else {
togglePicker.showPicker();
}
});
The reason I'm trying to do it this way is that there will be other triggers for subject on the page that will need access to the show/hide functions.
You can't access the functions inside the function, they are out of scope, you could attach them as properties to the wrapping function, but it looks like you just need an object
var toggleVis = {
showSomething: function() {
trigger.classList.add("active");
subject.classList.add("active");
},
hideSomething: function() {
trigger.classList.remove("active");;
subject.classList.remove("active");
}
}
Your togleVis variable is a function and not an object so you can't do toggleVis.hideSomething(). Try updating your code to :
var toggleVis = (function() {
return {
showSomething : function () {
trigger.classList.add("active");
subject.classList.add("active");
},
hideSomething : function () {
trigger.classList.remove("active");;
subject.classList.remove("active");
}
};
}());
With this toggleVis is now an object with two properties showSomething and hideSomething functions.

asp.net ajax property value timestamp is undefined

I have a problem with the value assignment and retrieval in asp.net ajax. The value of timestamp is undefined
Code:
/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("LabelTimeExtender1");
LabelTimeExtender1.ClientBehavior1 = function(element) {
LabelTimeExtender1.ClientBehavior1.initializeBase(this, [element]);
this._testelement=this.get_element();
this._timestamp= this.get_element().attributes['TimeStamp'].value;
alert(_timestamp);
},
LabelTimeExtender1.ClientBehavior1.prototype = {
initialize: function() {
LabelTimeExtender1.ClientBehavior1.callBaseMethod(this, 'initialize');
setInterval (this.timer,1000);
alert("after");
},
dispose: function() {
//Add custom dispose actions here
LabelTimeExtender1.ClientBehavior1.callBaseMethod(this, 'dispose');
},
timer: function(){
alert(this.timestamp);
var splitdate=this._timestamp.split(/[:]+/);
alert(splitdate);
var date= new Date(this._timestamp);
alert( date.toString());
var datenow= new Date ();
alert(datenow.toString());
this._element.innerText=" ";
alert(this._element);
if(date.getUTCFullYear<datenow.getUTCFullYear)
{
alert("year");
var myelement= this.get_element();
myelement .innerHTML= date.getUTCFullYear.toString();
}
if(date.getUTCMonth<datenow.getUTCMonth)
{
alert("month");
this.get_element().innerHTML=date.getUTCMonth.toString();
}
if(date.getUTCDay<datenow.getUTCDay)
{
this.get_element().innerHTML=date.getUTCDay.toString();
}
if(date.getUTCHours <datenow.getUTCHours )
{
this.get_element().innerHTML=date.getUTCHours .toString();
}
if(date.getUTCMinutes<datenow.getUTCMinutes)
{
this.get_element().innerHTML=date.getUTCMinutes.toString();
}
},
set_timestamp: function(value)
{
this._timestamp=value;
},
get_timestamp: function()
{
return this._timestamp;
}
}
LabelTimeExtender1.ClientBehavior1.registerClass('LabelTimeExtender1.ClientBehavior1', Sys.UI.Behavior);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Why is the value of _timestamp undefined?
I would suggest moving the code which sets this._timestamp into your initialize function.
My other suggestion is to use the getters and setters even within your own code to ensure encapsulation. So, the alerts would actually be alert(this.get_timestamp()). And, in your initialize function, you would call this.set_timestamp(this.get_element().attributes['TimeStamp'].value).
Thanks to the comment I see the problem is actually in the setInterval call. When you call window.setInterval(this.timer, 1000);, when the timer function is called this refers to window, not to your object. So instead, do something like this:
var self = this;
window.setInterval(function () {
self.timer();
}, 1000);
That will make this inside of timer() refer to the correct object.

Categories

Resources