Avoid using extra variable for storing reference in es6 - javascript

I'm already using react es6 but still in this case, I don't know how to avoid using that for this:
const that = this;
UploadApi.exec(file).then(data => {
that.setState({ loading : false});
});

In this example, you are already using arrow function, so storing the reference in a separate variable is not required. You can directly use this keyword like this:
//const that = this;
UploadApi.exec(file).then(data => {
this.setState({ loading : false});
});
Storing the reference in a separate variable required, when you use callback method like this:
const that = this;
UploadApi.exec(file).then(function(data){
that.setState({ loading : false});
});
But, you can avoid the extra variable by using .bind(this) with callback method, like this:
//const that = this;
UploadApi.exec(file).then(function(data){
this.setState({ loading : false});
}.bind(this));
Check this answer for complete detail, arrow function vs function declaration

You need to create yout UploadApi.exec that way so that after transpiling your javascript get created accordingly..like below
In you UploadApi
exec=(file:any):Q.Promise=>{
}
and then use it like below
UploadApi.exec(file).then(data => {
this.setState({ loading : false});
});

Related

how to use the google-translate-api translation outside the method?

I started using Cloud Google and implemented the translation API in my code but I can't use the response outside the callback.
methods:{
clicked(){
const text = "Olá";
const target = navigator.language;
googleTranslate.translate(text, target, function(err, translation){
console.log(translation.translatedText)
//this.newText = translation.translatedText;
});
//console.log(this.newText);
},
}
Show the error with or without the console.log. In the this.newText = translation.translatedText;
Error in render: "TypeError: Cannot read property 'newText' of undefined"
I would like to show the user the answer in the template. How can I do it?
Using the function keyword changes the 'this' context. You can either save 'this' outside of the function or use arrow functions.
Here's how you would use an arrow function
methods:{
clicked(){
const text = "Olá";
const target = navigator.language;
googleTranslate.translate(text, target, (err, translation) => {
console.log(translation.translatedText)
//this.newText = translation.translatedText;
});
//console.log(this.newText);
},
}

How to access 'this' keyword inside of static method in react native?

I am not able to access 'this' keyword in my static method in react- native, when I try to access it, it's thrown me error like 'this.setState not a function'.
Here is my code.
static getShiftStatus = () =>{
//for check shift start or not
Usermodal.getShiftStatus((isStatus) =>{
this.setState({isShiftStart: isStatus}) //error occure here.
console.log(a.state.isShiftStart)
})
}
this in the inner function points to something else.
You need to capture the this from the outside function.
static getShiftStatus = () =>{
var that = this; // capture here
Usermodal.getShiftStatus((isStatus) =>{
that.setState({isShiftStart: isStatus}) // use it here
console.log(a.state.isShiftStart)
})
}

Javascript/Typescript 'this' scope

I am working with Ionic2 and Meteor. I do however have a Javascript/Typescript issue relating to the scope of the this object.
I have read that I should use bind when I don't have handle on this at the appropriate level.
I probably don't understand the concept, because I try the following, but get an error trying to call a function.
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(function (message: Message) {
setLocalMessage.bind(message);
});
});
});
and
private setLocalMessage(message: Message): void {
this.localMessageCollection.insert(message);
}
I get the following error when I try build the app:
ERROR in ./app/pages/messages/messages.ts
(72,19): error TS2304: Cannot find name 'setLocalMessage'.
UPDATE
Thank you for the advise below.
I am now using the following, and it works.
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach((message: Message) => {
this.setLocalMessage(message);
});
});
I have read that I should use bind when I don't have handle on this at the appropriate level.
That's a bit outdated now, better have a look at How to access the correct `this` context inside a callback? these days which also shows you how to use arrow functions.
You're getting the error message because setLocalMessage is not a variable but still a property of this so you have to access it as such. There are basically three solutions in your case:
bind
messageData.find().forEach(this.setLocalMessage.bind(this));
the context argument of forEach (assuming it's the Array method):
messageData.find().forEach(this.setLocalMessage, this);
another arrow function:
messageData.find().forEach((message: Message) => {
this.setLocalMessage(message);
});
There are a few things wrong here.
In ES6 (and thus TypeScript), you need to refer to instance members using explicit this, such as this.setLocalMessage. Just writing setLocalMessage is invalid no matter where the code is.
Inside a function, the this object will probably not be what you expect anyway. You need to capture the this object from outside the function and put it in a variable, like so:
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let self = this;
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(function (message: Message) {
self.setLocalMessage(message);
});
});
});
Alternatively, you can use an arrow expression, in which this is the same as what it is in the code around it:
this.subscribe('messages', this.activeChat._id, this.senderId, () => {
this.autorun(() => {
let promiseMessages: Promise<Mongo.Collection<Message>> = this.findMessages();
promiseMessages.then((messageData: Mongo.Collection<Message>) => {
messageData.find().forEach(message => this.setLocalMessage(message));
});
});
});
It's not an issue of TypeScript itself. Without it, the code will just fail at runtime.

Store state of a JavaScript Object

Im trying to store the stats of 'this' in my javscript object so that later on in my application I can return 'this' to a previous state. I thought I could accomplish using a closure but so far I haven't successful. My idea was to do something like this
function SavedFeature() {
var self = this;
this.savedItem;
this.storeState = function() {
this.savedItem = storeClosure();
}
function storeClosure() {
var closure = self;
return function() {
return closure;
};
};
//other things the user can change...
}
so later on in my application if I needed to return to the point when I called storeState I could just do
//return the object I put in my closure
var backToNormal = savedFeature.savedItem();
that doesn't work though because any changes to my savedFeature object after I call storeState() are being reflected in the item im retrieving from called savedItem(). I'm guessing this is happening because closure is being set to a reference of self instead of copied to a new instance.
Is there anyway to store the state of my entire object in a closure like this or do I need to store this some other way.
The issue you are running into is that in js objects are passed by reference. This means that all changes performed on your object will apply to your obj.savedItem property.
Fix: Store a deep clone into obj.savedItem
this.storeState = function() {
this.savedItem = _.cloneDeep(this); // or _.clone(this, true);
}
cloneDeep is a lodash method, most js libs supply one of their own, e.g. jQuery's $.extend, etc.
You could easily roll your own deep clone function, look up the options on this thread.
A complete example with jQuery:
function SavedFeature() {
this.savedItem;
this.clone = function() {
return $.extend(true, {}, this);
},
this.storeState = function() {
this.savedItem = this.clone();
}
}
Doing it this way allows you adapt to different environments by changing your clone method as it is facading the used library method.
There are dozens of ways how to implement it. I will do just simple one. saving property.
Take into account if you want to save entire object you need to do deep copy of the object.
this is your feature:
function SavedFeature() {
this.savedItem = {'isNew': true};
this.stateMachine = new StateMachine();
}
this is some kind of state machine:
function StateMachine () {
var state = { 'isNew' : null};
function set(newState) {
state.isNew = newState.isNew;
}
function get() {
return state.isNew;
}
return {
get : get,
set : set
};
}
which, know how to store isNew property
and a working sample:
var savedFeature = new SavedFeature();
console.log(savedFeature.savedItem); // true by default
savedFeature.stateMachine.set(savedFeature.savedItem); // saving state.
savedFeature.savedItem.isNew = false; // modifying state
console.log(savedFeature.savedItem); // return false, because of statement above
var restoredState = savedFeature.stateMachine.get(); // restoring state
console.log(restoredState); // true
savedFeature.savedItem.isNew = restoredState.isNew;
console.log(savedFeature.savedItem); // true
you can adjust that code, and reach functionality whatever you need. hope that helps

If I create OOP JS code using prototype, how do I reference a class method from a loop?

I'll show you my code first:
function Messages(){
this.postResponseButton = '#postResponseButton';
$(document).ready(this.setEvents);
}
Messages.prototype.setEvents = function(){
$(self.postResponseButton).click(function(){
this.postResponse(); // ERROR HERE
});
}
Messages.prototype.postResponse = function(){
console.log('Post Response');
}
var messages = new Messages();
In the marked line ("ERROR HERE"), it's not recognizing the Messages.postResponse() function when I call it as this.postResponse(). I've also tried self.postResponse() without any success.
I'm sure it's a problem of scope; I'm just not sure how to refer to the actual object. Do I need to set var me = this and use that, or something?
Thanks for your time!
As you have said, the problem is that the context of the click event handler is not the same as the function in which it appears. Either bind (ES5, won't work in old browsers) the function to this:
Messages.prototype.setEvents = function(){
$(self.postResponseButton).click(function(){
this.postResponse();
}.bind(this));
}
Or save a reference to this and use that instead:
Messages.prototype.setEvents = function(){
var that = this;
$(self.postResponseButton).click(function(){
that.postResponse();
});
}
A third alternative would be to use $.proxy, which is effectively an alias for Function.prototype.bind including a fallback for old browsers:
Messages.prototype.setEvents = function(){
$(self.postResponseButton).click($.proxy(function(){
this.postResponse();
}, this));
}

Categories

Resources