How do I access class variables from an event in Javascript? - javascript

I'm using the prototype javascript libraries. My code is below. I've created a class and in that class I have created an event listener for one of the class methods. In that method I need to access both the attributes of the form element that triggers the event and the class properties. Currently, the code understands $(this).getValue() in the event because this is being assigned to the form element that triggered the event. How can I access the this.makingRequest and this.user properties from the event function? Can I pass them in as parameters somehow? If so, how? Nothing I've tried to this point works. Thanks for any help.
function AddressBookEntryObj(user, selectField)
{
this.selectField = selectField;
this.user = user;
this.makingRequest = false;
this.debugMode = false;
Event.observe(this.selectField, 'change', handleEvent);
}
//Prototype statements
AddressBookEntryObj.prototype.handleEvent = handleEvent;
//End prototype statements
function handleEvent()
{
try
{
if (!this.makingRequest)
{
this.makingRequest = true;
var ajax =
new Ajax.Request(
'/servlet/MyReallyCoolServlet',
{
method: 'get',
parameters: {
action: 'doGet',
whichFunc: 'MyReallyCoolFunction',
fieldValue: $(this).getValue(),
user: this.user
},
onCreate: handleAjaxCreate,
onComplete: handleChangeComplete
}
);
return true;
}
else
{
return false;
}
}
catch (ex)
{
alert("handleEvent Error: \r\n" + ex.toString());
}
}
Thanks!
Andrew

jsfiddle example
Take a look at this jsfiddle I made with your code. You needed to add "bind(this)" to your callback handler. Doing that will make "this" be your object and use "e.target" to access the html element.
_Michael

Firstly use:
AddressBookEntryObj.prototype.handleEvent = function()
{
}
Then this inside handleEvent should point to AddressBookEntryObj. To be sure it will work everywhere inside that function use something like:
var _this = this;
And then use _this inside any event handlers.

Related

Remove Listener when attached Function has Binding

Consider the following code:
class Test {
constructor() {
this.breakpoints = {};
}
add(options) {
// Register the media query
this.breakpoints[options.breakpoint] = window.matchMedia(options.breakpoint);
// Register the listener
this.breakpoints[options.breakpoint].addListener(this.breakpoint.bind(this));
}
remove(options) {
this.breakpoints[options.breakpoint].removeListener(this.breakpoint.bind(this));
}
breakpoint() {
// Do something...
}
}
In the above code, you will notice that I am attaching an event listener in the add method, and attempting to remove it in the remove method. Due to the code in the breakpoint method, the bind(this) part is absolutely crucial.
As a result of the bind(this) (I believe), the removeListener is not removing the media query listener. Is there any way to solve this?
I have also tried this (without the bind on remove):
remove(options) {
this.breakpoints[options.breakpoint].removeListener(this.breakpoint);
}
One option is to bind the breakpoint method to the context of the current instance in the constructor, so that referencing this.breakpoint always refers to the bound method later:
class Test {
constructor() {
this.breakpoint = this.breakpoint.bind(this);
this.breakpoints = {};
}
add(options) {
// Register the media query
this.breakpoints[options.breakpoint] = window.matchMedia(options.breakpoint);
// Register the listener
this.breakpoints[options.breakpoint].addListener(this.breakpoint);
}
remove(options) {
this.breakpoints[options.breakpoint].removeListener(this.breakpoint);
}
breakpoint() {
// Do something...
}
}

JS method binding with 2 different this

I have this small code:
ScenesController.prototype.viewAction = function() {
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
// the first click is just a sample, I need the same object in the Quailty Change method
$('.scenes_view_video_quailty').on('click', function() { echo($(this));});
$('.scenes_view_video_quailty').on('click', this.viewVideoQuailtyChange.bind(this));
};
ScenesController.prototype.viewVideoQuailtyChange = function(e) {
e.preventDefault();
if (!this.flash) {
echo(this);
echo($(this));
}
};
When I'm clicking the link, I would need pass 2 this variable to the QualityChange method. One with the object (in the bind) and the other is the click event, because I need the clicked element too.
I was trying with the .on('click', {$this: $(this)}, this.method) solution, but dosen't work, the evend.data.$this looks a different object.
I need the same object as I have in the first click method.
(echo = console.log)
Alias the this that refers to the current instance as something else (traditionally, self) and use this to refer to the clicked element
ScenesController.prototype.viewAction = function() {
var self = this;
this.flash = this.di.HelperFlash.hasSupport();
this.$playerElem = !this.flash? $('#html_player') : $('#flash_player');
$('.scenes_view_video_quailty').on('click', function() { echo(self, $(this));});
};
To call a method setting it's this reference you would use Function.apply, for example:
$('.scenes_view_video_quailty').on('click', function(){
self.viewVideoQuailtyChange.apply(self, [$(this)])
});
You can attach any number of variables with bind
You could have a proper method like:
ScenesController.prototype.viewVideoQuailtyChange = function(secondThis) {
}
then use the bind as:
this.viewVideoQuailtyChange.bind(this, $(this));
With this solution you do lose the event though, so it might need some more thought. I'll look into it and update the answer :)

js:scope of this inside an object on keypress event

Here is my JS simple script:
var Chat = function() {
console.log("init");
this.debug = function (txt) {
console.log(txt);
}
document.getElementById('shoutBoxInput').addEventListener("keypress", keyPressedFunction, false);
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value =""
this.debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
}
var chat = new Chat();
My problem comes from:
document.getElementById('shoutBoxInput').addEventListener("keypress", keyPressedFunction, false);
this.keyPressedFunction = function(e){
Error Uncaught ReferenceError: keyPressedFunction is not defined
If I use:
document.getElementById('shoutBoxInput').addEventListener("keydown", this.keyPressedFunction, true);
then keyPressedFunction is never called.
Fiddle: http://jsfiddle.net/ghLfhb6z/
Let's start with the problem, and then move to what's dangerous about your code.
The problem is that when you call addEventListener, this.keyPressedEvent doesn't yet exist:
// this.keyPressedFunction doesn't exist...so you are registering a 'keypress'
// event to undefined.
document.getElementById('shoutBoxInput').addEventListener("keypress",
keyPressedFunction, false);
// now you define this.keyPressedFunction
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
// so this is where you should be attaching it to the event
You may be thinking about JavaScript's hosting mechanism, and thinking "ah, the this.keyPressedFunction definition is being hoisted to the top of this function, so it's available for assigment." But hoisting only applies to variable and function definitions; what you're doing is assigning an anonymous function to a member property, so hoisting does not apply.
Now on to the dangerous:
When you use a method (a function property of an object) for a callback, the meaning of this is lost when that callback is invoked. (I know you aren't currently using this in your callback, but you probably will eventually!) In other words, when a key is pressed, and keyPressedFunction is called, the value of this won't be what you expect. The upshot of this is you have to be very careful assigning methods to callbacks or events. If you want to do it, you'll have to use Function.prototype.bind. Here's your code re-written in the correct order, and using bind:
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
document.getElementById('shoutBoxInput').addEventListener("keypress",
this.keyPressedFunction.bind(this), false);
place your function before you use its referenc...then use this.keyPressedFunction...then is 'keypress' a valid native js event ?
http://jsfiddle.net/ghLfhb6z/4/
yes there was the errors I told, in fact most important is to place your event handlers at the end, check the right event, and use this if the function is on this :
var Chat = function() {
console.log("init");
this.debug = function (txt) {
console.log(txt);
}
this.keyPressedFunction = function(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value =""
this.debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
// place this at the end
document.getElementById('shoutBoxInput').addEventListener("keydown", this.keyPressedFunction, false);
}
var chat = new Chat();
#dmidz has provided a correct answer that will solve your problem, but if your keyPressedFunction only needs to be referred to code inside your Chat() module, then you don't need to make them properties of this (Chat):
var Chat = function() {
console.log("init");
function debug(txt) {
console.log(txt);
}
function keyPressedFunction(e){
console.log("keyPressed");
}
this.sendText = function() {
var texte = document.getElementById('shoutBoxInput').value;
if (texte=="") return;
document.getElementById('shoutBoxInput').value ="";
debug("sendTexte:"+texte);
}
this.receiveText = function(username, texte) {
}
document.getElementById('shoutBoxInput')
.addEventListener("keypress", keyPressedFunction, false);
}
If you do this, then you don't necessarily have to declare your functions before you use them, but it would be good style to do so nonetheless.

Backbone.js calling function render from event handler

I got my view like this :
render:function(){
this.template = _.template(tpl.get('tplUsersManagement'));
this.$el.html(this.template({models : this.model.models}));
this.$el.i18n();
$('#formAddUser')
.on('invalid', function () {
var invalid_fields = $(this).find('[data-invalid]');
console.log(invalid_fields);
})
.on('valid', this.addUser);
return this;
},
addUser: function(event){
event.preventDefault();
var newUser = new UserModel({
. . .
});
var that=this;
newUser.save({},{
headers:{"X-Token":"theToken"},
statusCode:{
202: function(){
that.render();//here I want to call render function
}
}});
}
}
So I want to call my render function from my addUser function. I try to do it with this=that and then that.render but I got an error and it says that :
Uncaught TypeError: Object # has no method 'render'
I think its because in the event handler this become my form.
You are already aware of the context constraints and that's why you are using the var that = this trick, but there is another place you need to implement it:
var self = this; // I prefer "self" rather than "that"
$('#formAddUser').on('invalid', function () {
// handle invalid data
}).on('valid', function( ev ){
ev.preventDefault();
self.addUser();
return this;
});
The addUser function is part of your view module, but within the valid/invalid event handlers, the context (the this variable) is changed. You'll need to keep a reference of the correct context (var self = this;) before entering the scope of the event handler so that it can be used to call your addUser() function.
There will be 2 options.
1.Use event delegation of backbone view. It will be let you use your view object in event handler.
2.Bind your addUser function to this.
addUser: function() {
...
//do something
...
}.bind(this)

How to dynamically assign DOM event and then execute it?

i am trying to execute DOM events within a function that expects the event to handle, such as onmouseover, onclick and so on, by name as a function parameter like so:
...
doSomething(target, 'onmouseover');
doSomething : function(tgt, evt)
{
...
o.evt = function() {
alert(evt);
}
...
}
...
The assignment does not throw any errors, so i guess, it is syntactically correct, but it does also not do the alert. Why?
(Please do not recommend using frameworks. I would like to understand my mistake and how to get this managed.)
You can assign the event dynamically using the [] notation:
Demo
var obj = {
doSomething : function(tgt, evt)
{
tgt[evt] = function() {
alert(evt);
}
}
};
obj.doSomething(document.getElementById("test"), 'onmouseover');
​

Categories

Resources