Can you place a jQuery event inside of an object variable like so:
var taskObj = {
buttonClick:function() {
$("#button").click(function() {
alert("Something");
)};
}
}
If so how would you call it the method? Could I possibly bind it to an event? Reason I'm asking is because I'm trying to change some spaghetti code (alot) and make it a bit easier to maintain without having to rewrite it all. Any insight would be much appreciated.
Yes, you can do that. Your current object only has a click handler, so to actually bind it just run:
taskObj.buttonClick();
On DOM ready. To have an object hold the functions for handlers, you could do:
var taskObj = {
buttonClick:function() {
alert("Something");
}
}
And define the handler as:
$("#button").click(taskObj.buttonClick);
Related
Can I retrieve and modify a previously assigned event function?
For example I originally add an onclick event handler to a node, like this :
var someNode = document.getElementByID('someNode');
someNode.onclick = function(){
//some stuff
};
Ideally later I would need to get back this event and modify the "some stuff" code content.
Is it doable in javascript?
You can modify the onclick event. Simply assign that to a new function will do. However, similar to most dynamic languages, function is not a data structure that you can easily modify. So keeping the same function but modifying it is AFAIK impossible.
The way I would suggest is to create a new function for your use, and assign it to the onclick property. However, JS is a very nice language that provide closure to your variables. So you can make a function that return a function to fit your need if you need some flexibility.
It's not really clear what you are trying to accomplish. But do you mean something like that ?
var someNode = document.getElementByID('someNode');
let customizablePart = function (e) {
// do some stuff
}
someNode.onclick = function (e) {
// unchangeable instructions
customizablePart.call(this, e)
}
// later ...
customizablePart = function (e) {
// do new stuff
}
This is another Javascript closure question. I run the following code as soon as the document loads:
var handlers = (function () {
var clickHandler = function() { alert ('click!'); }
return {
clickHandler : clickHandler
}
}());
$('#element').addEventListener('click', handlers.clickHandler);
Then at some later point I want to replace the functionality of the handler and thus do something like:
handlers.clickHandler = function() { alert ('changed handler!'); }
From my understand of Javascript closures the event listener should keep a reference of the clickHandler function, and thus the functionality should change accordingly. Yet, this is not what happens. The event listener triggers the initial function. I have managed to achieve the result I want using eval but this feels like a hack. Is there a legitimate way to do what I want?
$('#element').on('click', /*the solution: */ () => handlers.clickHandler());
You need to resolve the identifier on execution of the handler, not on registration. That can be done by wrapping the call into a function, like i did above ( with an arrow function).
Assuming I have something like:
var MyApp = function() {
this.name = "Stacy"
}
MyApp.prototype.updateName = function(newname) {
this.name = newname;
}
In my main page I have a :
$(function () {
var instance = new MyApp();
})
I have a button event handler that would update the name:
$("#button").on("click", function(evt) {
// Update the name in MyApp to something else...
instance.name = "john" // I do not like using instance here, because it has to be "instance" has to be created before I can use it. I want to be able to make this independent of "instance" being created or not
});
What is the proper way to do it such that the button handler would update "MyApp" to have the correct name, without explicitly using the created "instance" of myapp as part of the button's click handler?
ideally I would like to shove that jquery event handler somewhere into "MyApp" such that I could do something like:
MyApp.prototype.events = function() {
$("#button").on("click", function(evt) {
this.name = "john"
});
}
Though it doesnt work because this refers to something else.
How to properly structure my application such that the event handler is more or less updating the properties of the "MyApp" so that it can be independent of the created "instance" (i.e. i no longer have to use the "instance.")?
First, if you create an setter function, it's a good idea to use it !! :D
$("#button").on("click", function(evt) {
// Update the name in MyApp to something else...
//instance.name = "john"
instance.updateName("john");
});
And then, it does not make sense to do put an event handler inside of a method of your object MyApp, since it will never bind the onclick event until you fire events()
Then... my way to organize this, is to use the jQuery document onload to bind all the DOM objects with the function of your applications. Usually something like this:
MYAPP = {};
MYAPP.say_something = function () {
alert('lol, you clicked me!');
};
...
$(function () {
$('#my_button').click(MYAPP.say_something);
$('#other_element').mouseenter(MYAPP.another_method);
});
And for big applications, where you have to work with a lot of elements, you can organize your code much better if you have a namespace for your DOM elements, something like this:
MYAPP.fetch_dom = function () {
return {
my_button: $('#my_button'),
other_element: $('#other_element')
};
};
And you can bind the events in a very neat way
$(function () {
// first initiate DOM
my_dom = MYAPP.fetch_dom();
// Then bind events
my_dom.my_button.click(MYAPP.say_something);
my_dom.other_element.mouseenter(MYAPP.another_method);
});
This way you don't have to look for the specific elements in the DOM from a thousand points of your programme, spreading hardcoded id's everywhere and performing noneffective searches against the DOM structure.
Finally, it is much better to use literals in JS rather than using the word new. JS is a prototypical OOP language and new is a little bit "against nature" that can be a pain in the ass.
I like to organize my javascript in namespace style like below. What I want to know : is there another (shorter?) way to call myFirstFunction() from mySecondFunction()? I tried this.myFirstFunction() and it's not working so maybe there's some kind of mysterious trick here that I don't know.
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
myNameSpace.myFirstFunction();
}
}
Thanks for your help as usual, people of SO! :)
As written in your example code, this.myFirstFunction() would work. Your code is likely simplified to illustrate your problem, so it would probably help to see the actual code to tell why it doesn't work with this.
One possible reason that it fails would be if the code where you call this.myFirstFunction() is inside a closure. If so, this would be a reference to the closing function, not your namespace and would therefore fail. See here for a contrived example based on your code to see what I mean. Again, having a look at the actual code would probably be helpful to diagnose what's going on.
Your suggestion to use 'this' should work. i.e.:
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
this.myFirstFunction();
}
}
Result:
myNameSpace.mySecondFunction() // "Hello World!".
If you want it to be shorter maybe you should consider the following pattern:
Javascript Design Pattern Suggestion
basically for your example:
var myNameSpace = (function()
{
function _myFirstFunction(){
alert("Hello World!");
}
function _mySecondFunction(){
_myFirstFunction();
}
return {
MyFirstFunction : _myFirstFunction,
MySecondFunction : _mySecondFunction
};
})();
I find this to be the cleanest pattern, also providing "private/public" variables in javascript that's otherwise pretty much impossible
In some cases the this keyword should work fine. If you explicitly call myNameSpace.mySecondFunction() then this.myFirstFunction() will execute as intended.
If you are using myNameSpace.mySecondFunction as an event handler it likely will not. In the case of an event handler you would need some way to refer to the namespace you want to use. A lot of JavaScript frameworks provide a way to define what the this keyword refers to. For example, in MooTools you can do myNameSpace.mySecondFunction.bind(myNameSpace) which will cause this to refer to myNameSpace inside mySecondFunction. If you are not using a framework you could make your event handler an anonymous function like:
document.getElementById('myId').addEventListener('click', function(e) {
myNameSpace.mySecondFunction.call(myNameSpace);
});
For more information on the call method I would refer to the MDC page for the call function or you could use apply which behaves similarly to call but passing an array of arguments for the second paramter rather than having a varargs like approach for additional parameters.
All of these suggestions are predicated on defining your namespace as #Harnish suggested:
var myNameSpace = {
myFirstFunction: function(){
alert("Hello World!");
},
mySecondFunction: function(){
this.myFirstFunction();
}
}
For more information about JavaScript function binding I'd highly suggest reading Justin's article on Function scope and binding in JavaScript
If you are attaching to event:
possible issue could be if you are attaching Namespace's function to event, like:
$(el).on("click", nameSpace.myFunc);
....
nameSpace = {
myFunc: function(){
this.anotherFunc();
}
}
that will throw error.
Solution 1
You may change this.anotherFunc() with nameSpace.anotherFunc()
Solution 2
You might change
$(el).on("click", nameSpace.myFunc);
// to ----->
$(el).on("click", function(){ nameSpace.myFunc(); } );
I have an onclick handler for an <a> element (actually, it's a jQuery-created handler, but that's not important). It looks like this:
function handleOnClick() {
if(confirm("Are you sure?")) {
return handleOnClickConfirmed();
}
return false;
}
From this function, the this object is accessable as the <a> element clicked. However, handleOnClickConfirmed's this is a Window element! I want handleOnClickConfirmed to have the same this as handleOnClick does. How would I do this?
(I know I can pass this as an argument to handleOnClickConfirmed, but some of my code already uses handleOnClickConfirmed and I don't want to have to rewrite those calls. Besides, I think using this looks cleaner.)
The following ought to do it:
function handleOnClick() {
if( confirm( "Sure?" ) ) {
return handleOnClickConfirmed.call( this );
}
return false;
}
The call() function attached to Function objects is designed to allow this; calling a function with a desired context. It's an extremely useful trick when setting up event handlers that call back into functions within other objects.
Rob's answer is the best answer for your problem, but I wanted to address something that you wrote in your original question:
I know I can pass this as an argument to handleOnClickConfirmed, but some of my code already uses handleOnClickConfirmed and I don't want to have to rewrite those calls.
JavaScript parameters are always optional, as far as the interpreter is concerned. For example if you have the function:
function MyFunction(paramA, paraB) {
// do nothing
}
All of these calls will execute without error:
MyFunction(1,2);
MyFunction(1);
MyFunction();
So you could modify handleOnClickConfirmed to accept what would essentially be an optional parameter. Like so:
function handleOnClickConfirmed(context) {
context = context || this;
// use context instead of 'this' through the rest of your code
}
Again, in this particular case, the call function is the best solution. But the technique I outlined above is a good one to have in your toolbox.