I have a method in my vue js element:
_deleteDesign : function(dsn)
{
//_deleteDesign
var url = '{{ url('/fapi/designsTmp/') }}/'+dsn.design_id;
axios.delete(url)
.then(function(){
this.$delete(this.creations, this.creations.indexOf(function(el){
return el.design_id = dsn.design_id;
}));
})
.catch(function(e){
alert('error deleting design');
})
debugger;
}
In this method I am using the indexOf function of Javascript, but vuejs reports me this error in the Chrome debugger:
this.creations.indexOf is not a function
What's the problem?
The this context has changed in the promise then handler because of new function declaration. One way to fix, would be to use ES6 arrow function which keeps the existing this binding for code within the function:
.then(() => {
this.$delete(this.creations, this.creations.indexOf(function(el){
return el.design_id = dsn.design_id;
}));
})
"indexOf" method can only be executed on variables that are type "string" or "array" (which is actually type "object").
So in your particular case "this.creations" must be either array or string. The issue is that you somehow ended up with the case when "this.creations" is not one of those types.
One possible solution is to add
console.log(typeof this.creations)
and monitor the type of this variable.
Also as previous answer mentioned the issue is that "this" changed context. One solution for this is to make copy of this object:
const self = this;
in the beggining of _deleteDesign function and to use "self" object instead of "this". Generally avoid using "this" object as much as possible.
Related
(I looked through similar questions and could not find an answer for my problem, so asking here.)
Why is the code below giving me the error "ReferenceError: myText is not defined"?
async myFunction(myText: string)
{
await this.asyncThing.evaluate(() => {
console.log(myText); // error is thrown here
});
}
Not sure why the closure should not still be active when the log function is called. Is there a workaround for this behavior?
It looks like you're using Puppeteer. Although the function you pass to evaluate looks like a regular closure, it is actually serialized and sent across the wire to the browser. This means that it doesn't actually close over/have access to the variables in the parent scope. Instead you must explicitly pass those variables as arguments to the evaluate function:
async myFunction(myText: string)
{
await this.asyncThing.evaluate((myTextInBrowser) => {
console.log(myTextInBrowser);
}, myText); // <- pass the variable in here
}
This is not called out very well in the documentation, but it is under "Passing arguments to pageFunction:" https://pptr.dev/#?product=Puppeteer&version=v2.1.1&show=api-pageevaluatepagefunction-args
The variable isn't visible inside the closure because the closure has no argument.
Consider
await this.asyncThing.evaluate((myText) => {
console.log(myText);
});
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 write a compatibility layer over a legacy library function whose internal signature looks like —
function legacyLibraryFunction(context) {
context.foo.bar = "data"
return context
}
The new system however, doesn't recommend assigning custom properties directly to context and instead recommends using the context.set() method.
How do I pass context from the new system to the old one so that context.foo="data" ends up called context.set('foo', data) instead?
I'm guessing I can use Object.defineProperty for this, but I don't really understand how.
Using a setter:
You can use a setter for this:
var wrappedContext = {
set foo(val) {
context.set('foo',val);
}
}
Note: I'm assuming context.foo instead of context.foo.bar because the second part of your question does not quite match the example code.
This will create an object (wrappedContext) that will have a foo property that will call context.set() when you assign a value to it. So then you can do:
legacyLibraryFunction(wrappedContext);
Using a proxy:
Since you're using node 6.6 you can also use a proxy:
var wrappedContext = new Proxy(context,{
set: function(obj, prop, value) {
obj.set(prop,value);
}
});
I have an object that is as follows:
{ except: player => ({ send :player.getSocket().broadcast.emit }) }
However this means that the this in the emit function is not the one it expects it to be (the broadcast object).
So I can do:
{ except: player => ({ send : (msg, data) => player.getSocket().broadcast.emit(msg, data) }) }
But this is ugly, especially if the arguments change.
So the alternative is:
{ except: player => ({ send : (t = player.getSocket().broadcast).emit.bind(t) }) }
But is there a tidier way of doing this, of assigning a function to an object while maintaining it's this as it's parent object.
You can specify who this will be by calling the function with apply or call. The first parameter to these methods will be this within the body of the function.
Using bind in order to maintain the scope of this is actually a good solution to your problem, the way I see it, it makes the code a lot more understandable because you can know to what object the function actually belongs, by using apply or call, when you read the code you wont know to what this the function/method belongs. As far as i know, bind is a pretty good solution to your problem here.
EDIT:
Everything is working as I expected. It was just an error calling the template method. I mistyped a () so I was trying template.method instead of template().method;
Anyway, if somebody would like to explain me if this is a valid design pattern or if I should go in a different way I will be definitively very grateful.
I read about the module pattern and I'm trying to implement it in some of my projects. The problem is that, in my opinion, I'm twisting it too much.
I'm inspired by the google apps script style where many objects returns other objects with methods and so on and they pass arguments.
something like
object.method(var).otherMethod();
What I want to achieve is a method that receives a parameter, sets an internal variable to that parameter and then returns an object with methods that uses that variable. Here is a minified version of the code that does not work:
var H_UI =(function (window) {
var selectedTemplate,
compileTemplate = function(){},
parseTemplateFields = function(){};
//template subModule. Collect: collects the template fields and returns a JSON representation.
var template = function(templateString){
if(templateString) selectedTemplate = templateString;
return {
getHtml:function(){ return compileTemplate( parseTemplateFields( selectedTemplate ) ) } ,
collect:function(){
.. operating over selectedTemplate ...
return JSON.stringify(result)}
} };
return {
template:template
};
})(window);
If I remove the line :
if(templateString) selectedTemplate = templateString;
and replace selectedTemplate with the parameter templateString in the methods of the returned object it works as expected. I know that I cant create a set() method in the returned object and use it like this
H_UI.template().set(var)
But I find it ugly. Anyway I think that I'm messing things up.
What is the best way to construct this?
If you want H_UI.template() creates a new object every time you call template() on it, your solution does not work. Because the variable selectedTemplate is created only once when the immediate function is called.
However if your intent is this your solution works fine. (variable selectedTemplate is shared for all calls to template()).
But if you want to every call to template creates a new object. Please tell me to write my idea
Is this a valid design pattern or if I should go in a different way
Yes, enabling chaining is definitely a valid design pattern.
However, if your template() method returns a new object, that object and its methods should only depend on itself (including the local variables and parameters of the template call), but not on anything else like the parent object that template was called on.
So either remove that "global" selectedTemplate thing:
var H_UI = (function () {
function compileTemplate(){}
function parseTemplateFields(){}
// make a template
function template(templateString) {
return {
getHtml: function(){
return compileTemplate(parseTemplateFields(templateString));
},
collect: function(){
// .. operating over templateString ...
return JSON.stringify(result)
}
}
}
return {template:template};
})();
or make only one module with with a global selectedTemplate, a setter for it, and global methods:
var H_UI = (function () {
var selectedTemplate;
function compileTemplate(){}
function parseTemplateFields(){}
return {
template: function(templateString){
if (templateString)
selectedTemplate = templateString;
return this; // for chaining
},
getHtml: function(){
return compileTemplate(parseTemplateFields(selectedTemplate));
},
collect: function(){
// .. operating over selectedTemplate ...
return JSON.stringify(result)}
}
};
})();
The difference is striking when we make two templates with that method:
var templ1 = H_UI.template("a"),
templ2 = H_UI.template("b");
What would you expect them to do? In a functional design, templ1 must not use "b". With the first snippet we have this, and templ1 != templ2. However, if .template() is a mere setter, and every call affects the whole instance (like in the second snippet), we have templ1 == H_UI and templ2 == H_UI.