I have a collection with a custom fetch function and a onFetchSuccess function.
The onFetchSuccess function needs to trigger some other events, so it is calling this.trigger and here is where it gets tricky.
It seems as if the context to this is lost as trigger is not found.
fetch(options = {}) {
console.log("fetching");
this.trigger(this.FETCH_START);
options.success = this.onFetchSuccess;
options.url = this.url;
Backbone.Collection.prototype.fetch.call(this, options);
console.log("fetched");
}
onFetchSuccess(model, response, options) {
console.log("success!")
this.trigger("change");
}
it just results in Uncaught TypeError: this.trigger is not a function
Am I missing something? From other answers(to different questions) it seems like this is the proper way to extend the fetch function
You need to change onFetchSuccess into an arrow function.
Arrow functions don't have their own context, unlike regular functions. That means the this of an arrow function is the this of the context in which the function was defined, while regular functions have their own this.
In you case you are using a regular function definition, the this of this.trigger is actually the this of the function, which doesn't have a trigger method.
If you are using the arrow function, the this will be the one containing a trigger method as you expected.
Related
javascript / Node.js
how can I retrieve a reference to this/object inside a promise.then ?
var controller = new MyController(params);
controller.action_send();
/////////////////////////////////
class MyController{
constructor(params)
{
this.params = params;
}
action_send()
{
var promise = ext_lib.send();
promise.then(
function(details) {
this.action_save(details);
//(node:27014) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'action_save' of undefined
});
}
action_save(details)
{
save (this.params, details);
}
}
a PHPStorm warning says
Warns against a common mistake of trying to reference a member of an ECMAScript class via this.
qualifier in a nested function that is not a lambda.
this in a nested function that is not a lambda is the function's own 'this' and doesn't relate to the outer class.
tks from now
Use an arrow function.
Unlike a regular function, an arrow function does not bind this. Instead, this is bound lexically (i.e. this keeps its meaning from its original context).
Here are more details about it Arrow Functions
You want to use an arrow function: (details) => {...}. This will make the scope the same as outside of the function, and so this should be your class.
I would also recommend looking up the difference between the function syntax and the => syntax, someone can probably explain it better than I.
Just to add to the above answers, this is how your code should look like
promise()
.then(function (results) {
}.bind(this)
).catch(...);
Make sure your bind is just before closing then()
I am doing some work with the GoogleMaps API and have created a module to hold some custom functions:
myFuncs = {
doStuff: function() {
console.log('I am doing stuff');
},
callStuff: function() {
console.log('I am calling doStuff');
this.doStuff();
}
}
This seems about right for what I need. But when I do this:
google.maps.event.addDomListener(document.getElementById('myButton'), 'click', myFuncs.callStuff);
When the button is clicked I get the following error:
Uncaught TypeError: Object #<HTMLButtonElement> has no method 'doStuff'
I understand here that the context of this has changed due to binding to the Dom object but I do not fully understand what is happening or how to solve it.
Try wrapping the function call in an anonymous function. For example:
google.maps.event.addDomListener(document.getElementById('scrollToForm'), 'click', function(){myFuncs.callStuff()});
I just ran this and it seems to be working.
EDIT
echoing this when you don't use the anonymous function shows that you are in the context opf whatever object you have bound to. Firing it from within the anonymous functions sets your context to the object you are calling. Not sure if it is the best way, but it does work. Instead of using this you could explicitly call out the object. IE
myFuncs = {
doStuff: function() {
console.log('I am doing stuff');
},
callStuff: function() {
console.log('I am calling stuff');
myFuncs.doStuff();
}
}
This takes out any way confusion in context.
I'm not sure if this has been asked before because I don't know what it's called.
But why wouldn't a method like this work? Below is just a general example
<script>
document.getElementById('main_div').onclick=clickie(argument1,argument2);
function clickie(parameter1,parameter2){
//code here
}
</script>
The code above would work fine if the event handler was assigned without parameters, but with parameters, it doesn't work. I think I read online that to overcome this problem, you could use closures. I'm assuming it's because of the parentheses ( ) that is calling the function immediately instead of assigning it to the event?
Because you're calling the function immediately and returning the result, not referencing it.
When adding the parenthesis you call the function and pass the result back to onclick
document.getElementById('main_div').onclick = clickie(); // returns undefined
so it's actually equal to writing
document.getElementById('main_div').onclick = undefined;
which is not what you want, you want
document.getElementById('main_div').onclick = clickie;
but then you can't pass arguments, so to do that you could use an anonymous function as well
document.getElementById('main_div').onclick = function() {
clickie(argument1,argument2);
}
or use bind
document.getElementById('main_div').onclick = yourFunc.bind(this, [argument1, argument2]);
It is however generally better to use addEventListener to attach event listeners, but the same principle applies, it's either (without arguments)
document.getElementById('main_div').addEventListener('click', clickie, false);
or bind or the anonymous function to pass arguments etc.
document.getElementById('main_div').addEventListener('click', function() {
clickie(argument1,argument2);
}, false);
The easiest way is:
yourElement.onclick = yourFunc.bind(this, [arg1, arg2]);
function yourFunc (args, event) {
// here you can work with you array of the arguments 'args'
}
When you say onClick = function() {...} you are registering your function with some internal JavaScript library. So when the "click" happens, that library invokes your function.
Now imagine you're the author of that library and someone registered their function with it. How would you know how many parameters to pass to the function? How would you know know what kind of parameters to pass in?
clickie(argument1,argument2)
This means to invoke the function and return its return value.
clickie
This simply is a reference to the function (doesn't invoke/execute it)
To bind an event to a element, you need to use either the attachEvent or addEventListener method. For example.
/* Non IE*/
document.getElementById('main_div').addEventListener('click', function () {}, false);
/* IE */
document.getElementById('main_div').attachEvent('onclick', function () {});
A function name followed by parentheses is interpreted as a function call or the start of a function declaration. The a onclick property needs to be set to a function object. A function declaration is a statement, and is not itself a function. It doesn't return a reference to the function. Instead it has the side effect of creating a variable in the global scope that refers to a new function object.
function clickie(param) { return true; }
creates a global variable named clickie that refers to a function object. One could then assign that object as an event handler like so: element.onclick = clickie;. An anonymous function declaration (often confused with a closure; for the difference see Closure vs Anonymous function (difference?)) does return a function object and can be assigned to a property as an event handler, as follows:
element.onclick = function(event) { return true; };
But this doesn't work:
element.onclick = function clickie(event) { return true;};
Why? Because function clickie(event) { return true;} is a statement, not a function. It doesn't return anything. So there is nothing to be assigned to the onclick property. Hope this helps.
I was trying the following:
f.addEventListener('submit',(function(frm){
var func = (function(e){somefunction(e,frm);})(e);
})(f),false);
But this is failing. I want to pass the form (f) as a static reference and the dynamic event object to the named function 'somefunction'.
What I have above isnt working, what is the right syntax for passing both?
The issue is that each of the functions is being called right away, with undefined actually being passed to addEventListener().
You'll want to instead return one of the functions without its calling parenthesis so the event can call it later:
f.addEventListener('submit', (function (frm) {
return function (e) {
someFunction(e, frm);
};
})(f), false);
Though, with event bindings, you may not necessarily need the closure, as the <form> will be the context (this) of the function passed:
f.addEventListener('submit', someFunction, false);
function someFunction(e) {
var frm = this;
// ...
}
not saure exactly what you are trying to do but, to looks like you are trying to manually pass in the form via the event handler. Instead save a reference and just refer to it in the handler such as
f.addEventListener('submit',function(){
var func = function(e){
somefunction(e,f);
};
},false);
you shouldn't need the self executing functions unless I am missing your intent here
I've got a function, like this:
menu[0].onclick = function() {
filters.reset_all();
clients.get();
}
So it's called when user clicks on the first menu element. Now I need to call it form the other place and what I've done is this:
if (li.onclick) { //li and menu[0] above are the same
li.onclick.call();
}
and it works well.
But now I need to pass some params to onclick function. I've tried this .call(some_param); but arguments array in onclick is empty.
What am I doing wrong?
edit: changed into this:
menu[0].onclick = function(arg) {
console.log(arg);
filters.reset_all();
clients.get();
}
and
li.onclick.call(li,param);
still nothing
The first argument to .call() is the value for the this pointer. The 2nd, 3rd, etc... arguments get passed to the function. You only need to use .call() if you're explicitly trying to set the this pointer. Otherwise, you can just directly call the function li.onclick().
Event handlers are generally called by the system and when that happens, they are passed the event object as the first argument. If you want a function available that takes different arguments, you should create your own function for that and not use the event handling function. Your event handler can also call this other function if desired.
menu[0].onclick = function() {
myFunc("aaa");
}
function myFunc(arg1) {
// do whatever here
filters.reset_all();
clients.get();
}
if (li.onclick) {
myFunc("bbb");
}
it should be
call(object, param1, param2, param3...);
In your case you can write
li.onclick.call(li, param1);
The first parameter of call() is the context (in this case this) the rest of the parameters go into the arguments array in order. If you use apply() instead of call then you have just two parameters: apply(this, arguments_array)