I'm using mootools:
I can't figure out how to use a variable when using an addEvent.
I want to use a for next loop to set values in a loop:
for (x=0;x<num;x++){
var onclickText = 'function (){onclick="addPageMoveEvent('+x+'"); }';
$('pageNum'+x).addEvent('click', onclickText);
}
>
I've search forums but not found any help.
Any help would be great.
Thanks
The addEvent method in MooTools accepts two arguments:
myElement.addEvent(type, fn);
Arguments:
type - (string) The event name to monitor ('click', 'load', etc) without the prefix 'on'.
fn - (function) The function to execute.
It does not take a string and passing a string such as "myFunction()" or "function() { myFunction(); }" will not work.
Since you are inside a loop, and the variable x will share the environment, you need to wrap its value inside another closure. One way is to use an additional closure:
$("pagenum" + x).addEvent("click", (function(value) {
return function() { addPageMoveEvent(value); }
})(x));
See all questions on StackOverflow regarding this particular problem of creating closures within loops.
Also worth checking out is this MDC article - Creating closures in loops: A common mistake
Warning: this first example will not work! Read on for an explanation.
You are confusing onclick HTML syntax with the MooTools addEvent. Try
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', 'addPageMoveEvent('+x+');');
}
This is simpler and cleaner, but might still not do what you want. This code will call the function addPageMoveEvent every time the link is clicked... is that what you want?
Since MooTools doesn't allow the above method, you must use the following:
A programmatically more interesting and less hazardous way to do the same would be:
factory = function (x) { return function() { addPageMoveEvent(x); }; };
for (var x=0;x<num;x++){
$('pageNum'+x).addEvent('click', factory(x));
}
This uses a factory for creating closures that hold your values of x... rather complex code, but it's the purist way. It also avoids using the scary eval that occurs because you feed addEvent a string. (It seems that MooTools doesn't like the other option anyway.)
That a use case for mootools pass method.
for (x=0;x<num;x++){
$('pageNum'+x).addEvent('click', addPageMoveEvent.pass(x));
}
Pass internally creates a closure that holds x in the his scope, so when the click event is fired it has the right value cause its not the same from the for loop.
Related
I have a function block which is dynamic and I need to call with either eval or new Function (preferably the latter). I want to pass in the event it was raised from
function MyFunc(e)
{
new Function("OtherFunc(e, 'abcde')");
}
I can't see how to do this, I have tried a few things such as bind(this), and with(this) but no joy. It's an unusual thing to want to do hence my confusion.
NB I can see it works with eval but new Function would be better if possible and I get the impression it should be, e.g.
How to use scope in JavaScript for Function constructor? (second answer)
Any suggestions? Thanks
(Added: Why I want to do this)
I'm using Kendo mobile buttons. I'm moving from this:
<button onclick="MyFunc(e)"/>
to this
<button data-click="Call" data-func="MyFunc(e)"/>
this is because onclick is not recommended with Kendo UI on iPhones
Don't use the function constructor. Really, really don't. It is eval by another name. Use a function declaration instead. That won't break scope or expect to be built up out of strings.
function MyTest(e) {
function callOtherFunc() {
OtherFunc(e, "abcde");
}
return callOtherFunc;
}
So basically, you have buttons right now with
onclick="MyFunc(e); OtherFunc('a')"
...and you want to change those to
data-click="Call" data-func="MyFunc(e); OtherFunc('a')"
...and you're trying to figure out how to write your Call function without any significant refactoring, continuing to use the strings as you have them now in the onclick.
I'm a bit confused by your use of e within onclick rather than event. As far as I'm aware, there's no e in-scope for onXyz handlers; the event is available as event, though. In the answer below, I've assumed event in onclick but e everywhere else; adjust as necessary.
Within those constraints, eval and new Function are indeed pretty much your only option. It's not more evil than onclick (which is also eval in disguise); eval used with strings you control isn't necessarily evil, it's just usually a last resort (kind of like with).
Based on the documentation, looks like your Call would look something like this:
function Call(e) {
var code = this.element.prop("data-func");
var f = new Function("e", code);
f.call(this, e);
}
That ends up running the code with this being the element that was clicked, and with e in scope to the code in the generated function.
I do not recommend this except perhaps as a temporary measure during proper refactoring, but within the constraints you've given, that's how I see it working. One reason I don't recommend it is that, as with onclick, all of your functions have to be globals (because other than the args you pass it, new Function only has access to globals), and globals are best avoided like the plague.
Live example (with some workaround for the fact I didn't include Kendo):
// Kendo calls the data-click function with this being something
// other than the element; but the element is available as `this.element`
function fakeKendo(e) {
Call.call({element: this}, e);
}
function Call(e) {
// (Using getAttribute instead of Kendo's prop here)
var code = this.element.getAttribute("data-func");
var f = new Function("e", code);
f.call(this, e);
}
function MyFunc(e) {
snippet.log("MyFunc: e.type = " + e.type);
}
function OtherFunc(arg) {
snippet.log("OtherFunc: arg is " + arg);
}
<p onclick="fakeKendo.call(this, event)" data-func="MyFunc(e); OtherFunc('a')">
Click me
</p>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
I'm a JavaScript slightly-more-than-beginner.
While reading the source for EventEmitter, I stumbled upon this interesting and, to me, elegant function:
// alias a method while keeping the correct context
function alias(name) {
return function aliasClosure() {
return this[name].apply(this, arguments);
};
}
I have two main questions:
First: why is the aliasClosure a named function? Is it useful in some way other than clarity? Also, is is really a closure? To me, it looks just like a semi-anonymous function.
Second: I rewrote this function like this:
function alias2(name) {
return this[name].bind(this);
}
Is it equivalent? I think it should, since the this context is the same and it's preserved in both versions.
Is there a reason to prefer one over the other?
No, these are not at all equivalent. From looking at the alias() function I think you would use it something like this:
> Array.prototype.strjoin = alias('join'); // make 'strjoin' an alias of 'join'
> [1, 2, 3].strjoin(" + ");
"1 + 2 + 3"
Using alias2() in the above code will not work.
Providing a name in a function instantiation expression makes a name available for stack traces. (I'm told newer debuggers don't always need it if the function is created in certain contexts, like a var initialization.)
I think the second is equivalent, mostly, though .bind() has some obscure special cases it handles.
edit wait - no, they're not equivalent. The first one involves this explicitly, and performs the lookup on each call. The first function doesn't need this to be bound to anything when it's called, while yours will throw an exception in that case.
One change that would make the two functions almost equal is wrapping bind inside a closure, like this:
function alias2(name) {
return function() {
return this[name].bind(this);
}
}
Still, bind behaves obscurely in rare cases.
I'm looking for a way to inject properties from "this" into local function scope, so i dont need write 'this.' when referencing to this properties.
Exact details are displayed in this code http://jsfiddle.net/wwVhu/3/, look at this part
...
//it's how it works
doStuff: function(param) { $('#output').html(this.value + param) }
//it's how i want it work - without referencing to this
//doStuff: function(param) { $('#output').html(value + param) }
I know it could be achieved by wrapping function code in "with(this) { ... }", but what are other options?
Writing "with(this)" in the beginning of every method or using js aop is what i'm trying to avoid.
Why would you want to do this? It's namespaced because it makes sence. this references to the element the listener is listening on. And it contains a lot more information than just the value.
If you want the value in another variable, you can do:
var value = this.value
There are basically four options:
You keep it the way it is. Context and local scope are different objects, combining them is bad practice and leads to collisions.
You add the value property as the 2nd parameter to the doStuff function.
You nickname this with a shorter identifier. I often find myself use $t.
You use with(this) $('#output').html(value + param);. This is a bad coding practice, as explained in 1). Your code becomes broken the second there is a param property in this.
Excuse me first. because i don't know this is question is valid or not. i if any one clear my doubt then i am happy.
Basically : what is the different between calling a method like:
object.methodname();
$('#element').methodname();
calling both way is working, but what is the different between, in which criteria make first and second type of methods. is it available in the core javascript as well?
In case if i have a function is it possible to make 2 type of method call always?
Can any one give some good reference to understand correctly?
Thanks in advance.
The first syntax:
object.methodName();
Says to call a function, methodName(), that is defined as a property of object.
The second syntax:
$('#element').methodname();
Says to call a function called $() which (in order for this to work) must return an object and then call methodname() on that returned object.
You said that "calling both way is working," - so presumably you've got some code something like this:
var myObject = $('#element');
myObject.methodname();
This concept of storing the result of the $() function in a variable is commonly called "caching" the jQuery object, and is more efficient if you plan to call a lot of methods on that object because every time you call the jQuery $() function it creates another jQuery object.
"Is it available in the core javascript as well?" Yes, if you implement functions that return objects. That is, JS supports this (it would have to, since jQuery is just a JS library) but it doesn't happen automatically, you have to write appropriate function code. For example:
function getObject() {
return {
myMethod1 : function() { alert("myMethod1"); return this; },
myMethod2 : function() { alert("myMethod2"); return this; }
};
}
getObject().myMethod1().myMethod2();
In my opinion explaining this concept in more depth is beyond the scope of a Stack Overflow answer - you need to read some JavaScript tutorials. MDN's Working With Objects article is a good place to start once you have learned the JS fundamentals (it could be argued that working with objects is a JS fundamental, but obviously I mean even more fundamental stuff than that).
The difference is very subtle.
object.methodname();
This is when JavaScript has the object at hand.
$('#element').methodname();
If you are using jQuery, you are asking jQuery to select the object that has the id of #element. After that you invoke the method on the selected object.
Could someone write down a very simple basic example in javascript to conceptualize (and hopefully make me understand) how the jQuery plugin design pattern is done and how it works?
I'm not interested in how creating plugin for jQuery (so no jQuery code here at all).
I'm interested in a simple explanation (maybe with a bit of Javascript code) to explain how it is done the plugin concept.
Plz do not reply me to go and read jQuery code, I tried, but I it's too complex, otherwise I would have not post a question here.
Thanks!
jQuery has a library of functions stored in an internal object named fn. These are the ones that you can call on every jQuery object.
When you do $("div.someClass") you get a jQuery object containing all <div> elements of that class. Now you can do $("div.someClass").each( someFunction ) to apply someFunction to each of them. This means, that each() is one of the functions stored in fn (a built-in one in this case).
If you extend (add to) the internal fn object, then you automatically make available your custom function to the same syntax. Lets assume you have a function that logs all elements to the console, called log(). You could append this function to $.fn, and then use it as $("div.someClass").log().
Every function appended to the fn object will be called in such a way that inside the function body, the this keyword will point to the jQuery object you've used.
Common practice is to return this at the end of the custom function, so that method chaining does not break: $("div.someClass").log().each( someFunction ).
There are several ways to append functions to the $.fn object, some safer than others. A pretty safe one is to do:
jQuery.fn.extend({
foo: function() {
this.each( function() { console.log(this.tagName); } );
return this;
}
})
Tomalak already posted almost everything You need to know.
There is one last thing that helps jQuery do the trick with the this keyword.
it's amethod called apply()
var somefunction=function(){
alert(this.text);
}
var anObject={text:"hello"};
somefunction.apply(anObject);
//alert "hello" will happen
It really helps in creating abstractions so that framework/plugin users would just use this as intuition tells them, whatever there is inside Your code
It works, as many other js frameworks, using javascript prototype orientation.
For instance you can declare a simple function
var alertHelloWorld = function() {
alert('hello world');
}
And then tie it to an existing object (including DOM nodes)
document.doMyAlert = alertHelloWorld;
If you do this
document.doMyAlert();
The alertHelloWorld function will be executed
You can read more about javascript object prototyping here