how to call this with libraries that changing the default this? - javascript

so I started to using interactjs
and I have this simple code:
class example {
registerTouchEvents() {
var self = this;
interact('.touchy').draggable({
onstart: self.onStart,
});
}
onStart(event) {
this.someAction();//<-- not working as this is interact object
}
someAction() {
console.log('touch has been started') //<-- I need to call this function
}
}
is there someway of calling the current object without using global variable?

Move the handler where you declare "self":
class example {
registerTouchEvents() {
var self = this
, onStart = function onStart(event) {
self .someAction();
}
;
interact('.touchy').draggable({
onstart: onStart,
});
}
someAction() {
console.log('touch has been started') //<-- I need to call this function
}
}

Related

How to get the parent function name of the function being called

I am trying to get the name of the parent function of the function being called.
For example if I have these functions:
var functions = {
coolfunction1: {
add: function () {
},
delete: function () {
},
save: function () {
}
},
coolfunction2: {
add: function () {
// i want to console.log() the name of the parent of this function,
// output: coolfunction2
},
delete: function () {
},
save: function () {
}
}
}
When I call functions.coolfunction2.add(), is there a way to log the name of the parent function that was run?
I know I can use the variable this but that only outputs the names of the children functions, add(), delete(), save().
How can I know that the coolfuntion2 was run?
I know this can be done manually, by rewriting the function name in the add() function, but is there a way to get the name dynamically?
You can add a getter to those methods as
Object.keys(functions).forEach(t =>
Object.keys(functions[t]).forEach(t2 => {
var func = functions[t][t2]; //save a reference to function since it won't be a function anymore once a getter is assigned
Object.defineProperty(functions[t], t2, {
get: function() {
console.log(t); //print the name of parent property or grand-parent property, etc
//func();
return func; //return the reference to this function
}
});
})
);
Demo
var functions = {
coolfunction1: {
add: function() {
},
delete: function() {
},
save: function() {
}
},
coolfunction2: {
add: function() {
console.log("a is invoked");
},
delete: function() {
},
save: function() {
}
}
};
Object.keys(functions).forEach(t =>
Object.keys(functions[t]).forEach(t2 => {
var func = functions[t][t2];
Object.defineProperty(functions[t], t2, {
get: function() {
console.log(t);
//func();
return func;
}
});
})
);
functions.coolfunction2.add();
functions.coolfunction2.add();
functions.coolfunction1.add();

Making a ES6 class out of Angular 1.5+ component and getting function callbacks to work

var app = angular.module('testApp', []);
class Component {
constructor(app, name, template, as, bindings) {
this.bindings = bindings;
this.config = {}
this.config.template = template;
this.config.controllerAs = as;
// pre-create properties
this.config.controller = this.controller;
this.config['bindings'] = this.bindings;
app.component(name, this.config);
console.log("Inside Component ctor()");
}
addBindings(name, bindingType) {
this.bindings[name] = bindingType;
}
controller() {
}
}
class App extends Component {
constructor(app) {
var bindings = {
name: "<"
};
super(app, "app", "Hello", "vm", bindings);
}
controller() {
this.$onInit = () => this.Init(); // DOESN'T WORK
/*
var self = this;
self.$onInit = function () { self.Init(); }; // DOESN'T WORK
*/
/*
this.$onInit = function () { // WORKS
console.log("This works but I don't like it!");
};
*/
}
Init() {
console.log("Init");
}
onNameSelected(user) {
this.selectedUser = user;
}
}
var myApp = new App(app);
<div ng-app="testApp">
<app></app>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
I'm trying to "classify" angular 1.5's .component(). I can get most of it figured out but when I try to assign a class method for $onInit it doesn't work. I've tried assigning to it and using arrow notation to call back to the class method but neither work. It does work if I assign an anonymous function directly but I don't want to do that. I want those functions to point to class methods because I find it cleaner.
So ultimately I want my App classes Init() method to get called for $onInit(). Is it possible?

Data is not recognised inside setTimeout inside another closure

I have my data, and I am trying to access it within an initializer inside setTimeout.
data() {
return { val: {} }
},
methods: {
test() {
console.log(this.val) // works
var self = this
setTimeout(function() {
console.log(this.val) // works
var check = this.myMethod()
$.validate({
onError: function($form) {
console.log(self.val) // doesn't work
}
})
}, 500)
},
myMethod() {
// some stuff
return true
}
}
This is the updated code. Using the var self = this approach, I am now gettign:
Uncaught TypeError: this.myMethod is not a function
data() {
return { val: {} }
},
methods: {
test() {
console.log(this.val) // works
var self = this;
setTimeout(function() {
console.log(self.val) // works
$.validate({
onError: function($form) {
console.log(self.val) // doesn't work
}
})
}, 500)
}
}
Try this. You often lose the value of this when calling functions within functions, so we store this in a variable to make it accessible from nested functions.
methods: {
test() {
console.log(this.val) // works
// for this -> self trick
let self = this;
setTimeout(function() {
console.log(self.val) // works
$.validate({
onError: function($form) {
console.log(self.val) // doesn't work
}
})
}, 500)
}
}

How to extends a javascript object?

I made a simple example of my problem with a babel object :
function babel(){
this.english = {
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { alert('T-shirt'); }
}
}
Now, I want to extends this object :
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('au revoir'); }
}
But what if I need to use an existing function define before ?
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { this.english.teeshirt(); }
}
What I could do is :
var say = new babel();
(function (_this) {
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
hello: function () { _this.english.hello(); }
}
})(say);
But in this case, I will always use the context of the say object, isn't it ?
The problem is, that in teeshirt function call this points to the french object, not babel object. If you have to access parent object, you should store reference to it somewhere. For example you can change your constructor like this:
function babel(){
this.english = {
parent: this,
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { this.parent.french.something(); }
}
}
But as you can see, there is a problem if you don't create object in constructor. I don't see any 'nice' approach, but you can do this:
function babel(){
this.english = {
parent: this,
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); }
teeshirt: function () { this.parent.french.something(); }
};
for (var i in babel.prototype) {
this[i].parent = this;
}
}
Then your french will look like this:
babel.prototype.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { this.parent.english.teeshirt(); }
}
While the question as asked does bring up all the fascinating issues with JavaScript's this and prototypal inheritance, I would suggest simplifying the whole problem and refactoring your objects. There are a couple ways to do this.
If the English version of teeshirt is the default, it should be in the object which is at the end of the prototype chain. That is, a French object would have as its prototype an English object. The French object would simply not contain a teeshirt member. This is similar to the way resource bundles work.
Now this idea may not work for you, because the relationship among the different bundles may be complex: perhaps sometimes Engish is a fallback sometimes but not other times. In this case, see if you can make your babel objects all singletons (i.e., just plain objects).
var babel = {}
babel.english = {
hello: function () { alert('hello'); },
goodbye: function () { alert('goodbye'); },
teeshirt: function () { alert('T-shirt'); }
}
babel.french = {
bonjour: function () { alert('bonjour'); },
aurevoir: function () { alert('aurevoir'); },
teeshirt: function () { babel.english.teeshirt(); }
}
babel.english.teeshirt();
babel.french.teeshirt();
Try it at http://jsfiddle.net/yRnLj/
I realize this looks like a complete avoidance of your interesting question. But if you only need one copy of each language bundle, it is a lot simpler. :-)

Javascript optional parameters for callbacks

I want to do something like $.ajax() success and error callbacks.
This is what I have so far:
var FileManager = {
LoadRequiredFiles: function (onLoadingCallback, onCompleteCallback) {
//Not sure what to do here
this.OnLoading = onLoadingCallback;
this.OnCompleteCallback = onCompleteCallback;
this.OnLoading();
this.OnComplete();
},
OnLoading: function () {
//empty by default
}
OnComplete: function () {
//empty by default
}
};
//I want to do something like this:
FileManager.LoadRequiredFiles({OnLoading: function() {
alert('loading');
}
});
How do I fix this up properly? I'm using FileManager as my namespace.
You can check if the functions are defined:
var FileManager = {
LoadRequiredFiles: function (config) {
config = config || {};
this.OnLoading = config.onLoadingCallback;
this.OnCompleteCallback = config.onCompleteCallback;
if(typeof this.OnLoading =='function') {
this.OnLoading();
}
//Or use the shortcut:
if(this.OnComplete) {
this.OnComplete();
}
}
};
FileManager.LoadRequiredFiles(
{
onLoadingCallback: function() {
alert('loading');
}
}
);

Categories

Resources