I need to found other way how to use javascript function.
var b = ce("input"); // Here I create element.
b.setAttribute("name", "g4");
b.value = "Centimetrais(pvz:187.5)";
b.onfocus = function() { remv(this); };
b.onchange = function() { abs(this); };
b.onkeypress = function() { on(event); }; // I need to change this place becose then I pass "event" argument function doesn't work.
ac(1, "", b); // Here I appendChild element in form.
Here is the function:
function on(evt) {
var theEvent = evt|| window.event;
var key = theEvent.keyCode || theEvent.which;
key = String.fromCharCode( key );
var regex = /^[0-9.,]+$/;
if( !regex.test(key) ) {
theEvent.returnValue = false;
if(theEvent.preventDefault) theEvent.preventDefault();
}
}
In IE and chrome it work but in mozilla doesn't. Any alternative how to fix it for firefox?
Also at this path other function working in mozilla if pass other argument like "car","dog",this. For example:
firstFunction();
function firstFunction() {
var b = ce("input"); // Here I create element.
b.onkeypress = function() { on("hi!"); };
ac(1, "", b); // Here I appendChild element in form.
}
function on(evt) {
alert(evt);
}
If I understand your question correctly, the problem is that you're not accepting the event argument in the main handler. E.g., in your first example:
b.onkeypress = function() { on(event); };
it should be
b.onkeypress = function(e) { on(e || window.event); };
// Changes here --------^ and --^^^^^^^^^^^^
You're doing that in on, but in on, it's already too late, you've lost the argument provided to the onXYZ function.
The reason your code works in Chrome and IE is that IE uses a global event object instead of (or in modern versions, in addition to) the one it actually passes into the handler, and Chrome replicates that behavior for maximum compatibility with websites that expect that. Firefox does not.
Related
I am trying to access the properties of the MainObj inside the onclick of an elem.
Is there a better way to design it so the reference wont be to "MainObj.config.url"
but to something like this.config.url
Sample code:
var MainObj = {
config: { url: 'http://www.mysite.com/'},
func: function()
{
elem.onclick = function() {
var url_pre = MainObj.config.url+this.getAttribute('href');
window.open(url_pre, '_new');
};
}
}
'this' inside the object always refers to itself (the object). just save the context into a variable and use it. the variable is often called '_this', 'self' or '_self' (here i use _self):
var MainObj = {
config: { url: 'http://www.mysite.com/'},
func: function()
{
var _self = this;
elem.onclick = function() {
var url_pre = _self.config.url+this.getAttribute('href');
window.open(url_pre, '_new');
};
}
}
You can use the Module pattern:
var MainObj = (function () {
var config = { url: 'http://www.mysite.com/'};
return {
func: function() {
elem.onclick = function() {
var url_pre = config.url+this.getAttribute('href');
window.open(url_pre, '_new');
};
}
};
}());
First we define the config object in the local function scope. After that we return an object literal in the return statement. This object contains the func function which later can be invoked like: MainObj.func.
There is, most certainly, a better way... but I must say: binding an event handler in a method is -and I'm sorry for this- a terrible idea.
You might want to check MDN, about what it has to say about the this keyword, because this has confused and tripped up many a man. In your snippet, for example, this is used correctly: it'll reference elem. Having said that, this is what you could do:
var MainObj = (function()
{
var that = {config: { url: 'http://www.google.com/'}};//create closure var, which can be referenced whenever you need it
that.func = function()
{
elem.onclick = function(e)
{
e = e || window.event;
window.open(that.config.url + this.getAttribute('href'));
};
};
return that;//expose
}());
But as I said, binding an event handler inside a method is just not the way to go:
MainObj.func();
MainObj.func();//shouldn't be possible, but it is
Why not, simply do this:
var MainObj = (function()
{
var that = {config: { url: 'http://www.google.com/'}};
that.handler = function(e)
{
e = e || window.event;
window.open(that.config.url + this.getAttribute('href'));
};
that.init = function(elem)
{//pass elem as argument
elem.onclick = that.handler;
delete that.init;//don't init twice
delete that.handler;//doesn't delete the function, but the reference too it
};
return that;//expose
}());
MainObj.init(document.body);
Even so, this is not the way I'd write this code at all, but then I do tend to over-complicate things every now and then. But do look into how the call context is determined in JS, and how closures, object references and GC works, too... it's worth the effort.
Update:
As requested by the OP - an alternative approach
(function()
{
'use strict';
var config = {url: 'http://www.google.com/'},
handlers = {load: function(e)
{
document.getElementById('container').addEventListener('click',handlers.click,false);
},
click: function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
//which element has been clicked?
if (target.tagName.toLowerCase() === 'a')
{
window.open(config.url + target.getAttribute('href'));
if (e.preventDefault)
{
e.preventDefault();
e.stopPropagation();
}
e.returnValue = false;
e.cancelBubble = true;
return false;//overkill
}
switch(target.id)
{
case 'foo':
//handle click for #foo element
return;
case 'bar': //handle bar
return;
default:
if (target.className.indexOf('clickClass') === -1)
{
return;
}
}
//treat elements with class clickClass here
}
};
document.addEventListener('load',handlers.load,false);//<-- ~= init
}());
This is just as an example, and it's far from finished. Things like the preventDefault calls, I tend to avoid (for X-browser compatibility and ease of use, I augment the Event.prototype).
I'm not going to post a ton of links to my own questions, but have a look at my profile, and check the JavaScript questions. There are a couple of examples that might be of interest to you (including one on how to augment the Event.prototype in a X-browser context)
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript prototype ‘this’ issue
I have an event listener which of course calls a method on an event. This method tries unsuccessfully to hold a reference to the holding objects this so that it can access other properties of the object.
There is a single comment denoting where the behavior is not understood. this_hold.Name is not accessible there as I thought it would be.
/*MUserExist
**
**
**
*/
$A.module({
Name: 'MUserExist',
S: {
ClientStorage: SClientStorage,
ComMessage: SComMessage,
ComText: SComText,
DynSma: SDynSma,
DynTwe: SDynTwe,
DynArc: SDynArc,
AniMorphLabel: SAniMorphLabel,
AniFlipPage: SAniFlipPage
},
E: {
but: $A('#ue_but')[0],
text: $A('#ue_go')[0],
form: $A('#ue_fo')[0],
check: $A('#ue_check')[0]
},
J: {
box: $('#ue_box')
},
init: function () {
var pipe = {},
this_hold = this;
this.J.box.draggable();
this.E.but.addEventListener("click", function () {
pipe = $A.definePipe(this_hold.Name);
$A.machine(pipe);
}, false);
this.E.text.addEventListener("keypress", this.enter, false);
this.S.AniMorphLabel.run(["ue_email",
"ue_email_lab",
"ue_go",
"ue_pass_lab"
]);
},
enter: function (event) {
var pipe = {},
this_hold = this;
if (event.keyCode === 13) {
pipe = $A.definePipe(this_hold.Name); // fails here what does 'this' point to?
$A.machine(pipe);
event.preventDefault();
}
},
pre: function (pipe) {
var form_elements = this.E.form.elements,
text_object = new this.S.ComText(form_elements);
pipe.enter = this.enter;
if ($A.Un.get('load') === '1') {
if (!text_object.checkFull()) {
pipe.type = 'empty';
return this.S.ComMessage.message(pipe);
}
if (!text_object.checkPattern('email')) {
pipe.type = 'email';
return this.S.ComMessage.message(pipe);
}
if (!text_object.checkPattern('pass')) {
pipe.type = 'pass';
return this.S.ComMessage.message(pipe);
}
}
pipe.page = text_object.getArray();
pipe.proceed = true;
pipe.page.remember = this.E.check.checked;
return pipe;
},
post : function (pipe) {
if (pipe.proceed === true) {
this.S.ComMessage.resetView('ue_email');
this.S.ComMessage.resetView('ue_go');
this.S.ClientStorage.setAll(pipe.server.smalls);
this.S.DynSma.run(pipe.server.smalls);
this.S.DynArc.run(pipe.server.arcmarks);
this.S.DynTwe.run(pipe.server.tweets);
this.S.AniFlipPage.run('ma');
} else {
return this.S.ComMessage.message(pipe);
}
}
});
this likely points to the DOM node from which the event was triggered. Have you tried writing this to the console to inspect it?
console.log(this);
this is the DOM object that generated the event. It is NOT your javascript object.
When you pass this.enter as the method for the event handler, the method enter does not stay bound to your object. If you want that to happen, you have to change your code to cause that to happen by doing something like this:
// save local copy of my object so I can refer to it in
// the anonymous function
var obj = this;
this.E.text.addEventListener("keypress", function(event) {obj.enter(event)}, false);
It is important to remember that this is set by the caller of a method/function. In this case the caller of the event handler is the event sub-system in the browser. It does not know what your object is and it's designed behavior is to set this to the DOM object that caused the event. So, if you want to call your obj.enter method, you can't just pass enter as the event handler. Instead, you make a separate function that gets called as the event handler and you then call obj.enter() from that using your object as the base so that this gets set correctly.
Another solution would be to use .bind() which also creates a stub function that binds the right this to a function call, but I don't use .bind() myself because it doesn't work in all older browsers.
Try to change how the event is being bound
this.E.text.addEventListener("keypress", this.enter, false);
to
var that = this;
this.E.text.addEventListener("keypress", function(event) {
that.enter(event);
}, false);
I am trying to do something simple: I have a bunch of Images which are being load through JS.
I attach an event listener to the load event, and after the Image is being loaded, in the listener function I would like to get the calling Image and retrieve properties from it.
Here is my code, simplified:
function loadImages() {
for (var i = 0; i < arrDownloadQueueBasic.length; i++) {
var path = arrDownloadQueueBasic[i].path;
var img = new Image();
img.type = arrDownloadQueueBasic[i].type;
img.attachEvent(img, 'load', setBasicElement);
img.src = path;
}
}
function setBasicElement(e) {
var caller = e.target || e.srcElement;
alert(caller); // THIS DOESNT WORK - RETURN NULL
alert(caller.type) // OF COURSE THIS DOESNT WORK AS WELL...
}
There are a couple of things that you need to correct. First, the attachEvent method should not be used for browsers other than IE. You should structure your code to check if the method is implemented and then act accordingly like so:
if(img.addEventListener) {
img.addEventListener('load', setBasicElement, false);
}
else if(img.attachEvent) {
img.attachEvent('onload', setBasicElement);
}
else {
img.onload = setBasicElement;
}
The other issue is that you need to prefix the event name with "on" when using attachEvent.
EDIT
You can get the caller by using the following code in the setBasicElement function:
var caller = e.target || e.srcElement || window.event.target || window.event.srcElement;
Here is a working example - http://jsfiddle.net/BMsXR/3/
Try this:
var caller = window.event ? window.event.srcElement : e.target;
If I remember rightly IE doesn't pass the event object as a parameter when you've used attachEvent(), but it has a global event object.
In trying to make my Javascript unobtrusive, I'm using onLoads to add functionality to <input>s and such. With Dojo, this looks something like:
var coolInput = dojo.byId('cool_input');
if(coolInput) {
dojo.addOnLoad(function() {
coolInput.onkeyup = function() { ... };
});
}
Or, approximately equivalently:
dojo.addOnLoad(function() {
dojo.forEach(dojo.query('#cool_input'), function(elt) {
elt.onkeyup = function() { ... };
});
});
Has anyone written an implementation of Ruby's andand so that I could do the following?
dojo.addOnLoad(function() {
// the input's onkeyup is set iff the input exists
dojo.byId('cool_input').andand().onkeyup = function() { ... };
});
or
dojo.byId('cool_input').andand(function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
I don't know Dojo, but shouldn't your first example read
dojo.addOnLoad(function() {
var coolInput = dojo.byId('cool_input');
if(coolInput)
coolInput.onkeyup = function() { ... };
});
Otherwise, you might end up trying to access the element before the DOM has been built.
Back to your question: In JavaScript, I'd implement andand() as
function andand(obj, func, args) {
return obj && func.apply(obj, args || []);
}
Your example could then be written as
dojo.addOnLoad(function() {
andand(dojo.byId('cool_input'), function() {
this.onkeyup = function() { ... };
});
});
which isn't really that much shorter than using the explicit if statement - so why bother?
The exact syntax you want is not possible in JavaScript. The way JavaScript executes would need to change in a pretty fundamental fashion. For example:
var name = getUserById(id).andand().name;
// ^
// |-------------------------------
// if getUserById returns null, execution MUST stop here |
// otherwise, you'll get a "null is not an object" exception
However, JavaScript doesn't work that way. It simply doesn't.
The following line performs almost exactly what you want.
var name = (var user = getUserById(id)) ? user.name : null;
But readability won't scale to larger examples. For example:
// this is what you want to see
var initial = getUserById(id).andand().name.andand()[0];
// this is the best that JavaScript can do
var initial = (var name = (var user = getUserById(id)) ? user.name : null) ? name[0] : null;
And there is the side-effect of those unnecessary variables. I use those variables to avoid the double lookup. The variables are mucking up the context, and if that's a huge deal, you can use anonymous functions:
var name = (function() {return (var user = getUserById(id)) ? user.name : null;})();
Now, the user variable is cleaned-up properly, and everybody's happy. But wow! what a lot of typing! :)
You want dojo.behavior.
dojo.behavior.add({
'#cool_input': {
onKeyUp: function(evt) { ... }
}
});
How about something like this:
function andand(elt, f) {
if (elt)
return f(elt);
return null;
}
Call like this:
andand(dojo.byId('cool_input'), function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
As far as I know there isn't a built-in JavaScript function that has that same functionality. I think the best solution though is to query by class instead of id and use dojo.forEach(...) as you will be guaranteed a non-null element in the forEach closure.
You could always use the JavaScript equivalent:
dojo.byId('cool_input') && dojo.byId('cool_input').whateverYouWantToDo(...);
I've never used dojo, but most javascript frameworks (when dealing with the DOM) return the calling element when a method is called from the element object (poor wording, sorry). So andand() would be implicit.
dojo.addOnLoad(function() {
dojo.byId('cool_input').onkeyup(function(evt) { /*event handler code*/
});
});
For a list:
Array.prototype.andand = function(property, fn) {
if (this.filter(property).length > 0) this.map(fn);
}
I know I could do this with closures (var self = this) if object was a function:
click here
<script type="text/javascript">
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
return false;
},
load : function () {
document.getElementById('x').onclick = this.handle_click;
}
};
object.load();
</script>
The simplest way to bind the call to handle_click to the object it is defined in would be something like this:
var self=this;
document.getElementById('x').onclick =
function(e) { return self.handle_click(e) };
If you need to pass in parameters or want to make the code look cleaner (for instance, if you're setting up a lot of similar event handlers), you could use a currying technique to achieve the same:
bind : function(fn)
{
var self = this;
// copy arguments into local array
var args = Array.prototype.slice.call(arguments, 0);
// returned function replaces first argument with event arg,
// calls fn with composite arguments
return function(e) { args[0] = e; return fn.apply(self, args); };
},
...
document.getElementById('x').onclick = this.bind(this.handle_click,
"this parameter is passed to handle_click()",
"as is this one");
So, the event handler part wires up just fine (I tested it myself) but, as your comment indicates, you have no access to the "y" property of the object you just defined.
This works:
var object = {
y : 1,
handle_click : function (e) {
alert('handling click');
//want to access y here
alert(this.y);
return false;
},
load : function () {
var that = this;
document.getElementById('x').onclick = function(e) {
that.handle_click(e); // pass-through the event object
};
}
};
object.load();
There are other ways of doing this too, but this works.
I see how to do it with Jason's latest one. Any way to do it without the anonymous function?
We can directly pass an object with a handler method thanks to AddEventListener, and you will have access to its attributes:
http://www.thecssninja.com/javascript/handleevent
Hope this will help those who, like me, will look for this topic some years after!