I'm using es6 javascript with babel and trying to make an ajax call using xhr using two function but getting an error Uncaught TypeError: this.post is not a function
What is the correct syntax to make a call to a function from another function defined in the same class in es6 javascript?
Thanks for your answer this is my code
import alt from '../../alt';
import cookie from 'react-cookie';
class LoginActions {
constructor(){
this.generateActions(
'updatePassword',
'updateName',
'loginSuccess',
'loginFail',
'remember'
);
}
// Generic get request
post(url, data, callback) {
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
callback(null, xhr.responseText);
} else {
callback(xhr.statusText);
}
}
};
xhr.send(data);
}
// Get actual content
login(name, password, remember) {
var data = "name="+name+"&password="+password+"&remember="+remember;
this.post('api/login', data, function(err, data) {
if (!err) {
this.actions.loginSuccess(data.message);
} else {
this.actions.loginFail(JSON.parse(data.message));
}
}).bind(this);
}
}
export default alt.createActions(LoginActions);
Edit1: This is how I call login function / also passed data to xhr request above
handleSubmit(event){
event.preventDefault();
var name = this.state.name;
var password = this.state.password;
var remember = this.state.remember;
LoginActions.login(name, password, remember);
}
Your methods login() and post() are instance methods, not static methods. So you have to create an instance of your LoginActions object with new in order to properly call those methods on that object.
Or if you don't actually need an instance with instance data, then make all the methods static and refer to them as LoginActions.post() and LoginActions.login(), not using this.
Instead, you're trying to mix and match. You're calling LoginActions.login() which is a static type call and then inside of login(), you're trying to reference this which assumes an instance.
Give these things a try:
As #jfriend00 suggested, create an instance of LoginAction class and call login method on that:
var loginAction = new LoginActions();
loginAction.login(name, password, remember);
define generateActions method in LoginActions class.
this.post('api/login', data, function(err, data) {
if (!err) {
this.actions.loginSuccess(data.message);
} else {
this.actions.loginFail(JSON.parse(data.message));
}
}).bind(this);
Here, you seem to be trying to bind this to the callback. But actually you are binding this to the return value of post method. To bind this to the callback,
this.post('api/login', data, function(err, data) {
if (!err) {
this.actions.loginSuccess(data.message);
} else {
this.actions.loginFail(JSON.parse(data.message));
}
}.bind(this));
Notice function(){}.bind instead of the post(function(){}).bind
Related
I'm running a Vue script with a text box and submit button, I'm calling an api to POST what I write in the textbox to the api and to return information back from the API, I'm getting this error mentioned in the title eventhough I've written the Javascript functions in vue as it should be?
With the script I'm first setting up a new XMLHttpRequest, initiating the header and api key for both GET and POST methods. I've then created 2 functions to get the data from the textbox and send them to the API, then making another button with the other function to send back the data.
I went through this approach because I kept getting a CORS issue and the API needed me to declare an access control origin header, is there anything I've done wrong with this code? Any help would be greatly appreciated
<script>
export default {
name: 'ProperForm'
}
methods: {
StartClient: function () {
this.get = function(Url, Callback){
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("GET", Url, true);
aHttpRequest.setRequestHeader("X-Api-Key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(null);
}
this.post = function(Url, message, Callback) {
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("POST", Url, true);
aHttpRequest.setRequestHeader("x-api-key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(message);
}
}
var client = new StartClient();
submitData: function () {
document.getElementById('inputBox').disabled = true;
var targetInputButton = document.getElementById("inputBox").value;
var message = '{"targetInputButton":"' + targetInputButton + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/start-trace', message, function(response) {
document.getElementById('jobId').innerHTML = response;
});
}
sendBackData: function () {
var jobId = document.getElementById("jobId").innerHTML;
var message = '{"jobId":"' + jobId + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/check-trace', message, function(response) {
document.getElementById('report').innerHTML = response;
});
}
}
</script>
New way I wrote var client:
StartClient: function () {
var client
},
You need put your methods object inside export and split the methods to comma
<script>
export default {
name: 'name',
methods:{
foo(){
},
bar(){
}
}
}
UPD: var client = new StartClient();
defined outside the method
I need to make an API call. The API consists of several arrays containing objects and the objects have 18 keys which I need to display.
How can I just display everything? I have tried doing fetch and ajax calls but none of them seem to work. What am I doing wrong here? Thanks beforehand.
async function events() {
return $.ajax("/api/address");
getEvents: function getEvents() {
return $.ajax("/api/address");
};
targetMarket: function targetMarket(id, events) {
return events.filter(function(event) {
return event.eventID === id;
});
};
eventsName: function eventsName(events, name) {
return events.filter(function(event) {
return events.event.eventID === events.eventID;
});
};
}
API calls can look a little intimidating starting off, keep at it!
Here's an example of getting simple data using an Ajax call to an API. This is in plain JavaScript, no libraries needed:
let cryptoData;
function ajaxGet(url) {
return new Promise(function(resolve, reject) {
let req = new XMLHttpRequest();
req.open('GET', url);
req.onload = function() {
if (req.status === 200) {
resolve(req.response);
cryptoData = JSON.parse(req.response); // the API response with the data is here (req.response). We use the JSON.parse() method to convert req.response string into a JSON object, since it originally comes in as a string.
showAjaxData();
} else {
reject(Error(req.statusText));
}
};
req.onerror = function(err) {
reject(Error("Looks like we've got an error..."));
};
req.send();
});
}
function showAjaxData() {
console.log(cryptoData[0]);
}
ajaxGet(`https://api.coinmarketcap.com/v1/ticker/bitcoin/`);
You can see the code in action at this JS Fiddle demo. Just remember to open the browser console to view the logged API data.
Feel free to check out this w3schools tutorial on Ajax calls.
Hope this helps :)
Im trying to set a modules variable/property from a nested function (basically a xhr callback (Api.get()) inside that module (in the init() function), but it does not work and I can not figure out why.
//posts
var Posts = (function() {
//array of all posts objects
var data = null;
//initialize the posts module
var init = function(callback) {
if(data === null) {
//load all posts
loadAll(function(response){
// data = JSON.parse(response)
var posts = JSON.parse(response)
//create array
data = posts;
// call callback
console.log(data)
callback()
})
}
}
// return all posts from api as json
var loadAll = function(callback) {
Api.get('/api/posts/get', function(response) {
callback(response)
})
}
//public interface
return {
data: data,
init: init,
loadAll: loadAll
}
})();
After calling Posts.init() I log Posts.data to the console, but it is still null. However, console.log(data) inside the init() method logs the expected array of objects im trying to assign to Posts.data. It seems that data inside the callback is another variable than Posts.data. Can someone please explain why and if possible, provide a solution for setting the modules data property inside Api.get()?
You need to have a reference to the return object so you can alter its data property after you've returned the object. One way to do this would be to create an object with the methods and data and return that object. Then you can refer to its data property internally with this.data:
// Fake API
let Api = {
get(url, cb) {
cb('["testdata"]')
}
}
//posts
var Posts = (function() {
//array of all posts objects
return {
data: null,
init(callback) {
if (this.data === null) {
//load all posts
this.loadAll((response) => { // arrow function needed here for correct `this` binding
var posts = JSON.parse(response)
//create array
this.data = posts; // add data
callback()
})
}
},
loadAll(callback) {
Api.get('/api/posts/get', function(response) {
callback(response)
})
}
}
})();
console.log("initial posts data: ", Posts.data)
Posts.init(() => console.log("After init():", Posts.data))
If you do it this way, you don't actually need the IEFE unless you plan on making multiple objects. You can just use Posts = {/* rest of the data and methods */}. This would also work well as a class instead of a plain object.
I have three files: user.js, influencer.js, & validate.js
In user.js, I import ./influencer (as var = influencer) & ./validate (as var = validate).
My function in user.js:
addAccount: function(){
return functions.database.ref('/acct/{accountID}/name/').onCreate(event => {
var accountID = event.params.accountID;
var name = JSON.stringify(event.data.val()).replace(/['"]+/g, '');
console.log("New Account Added ("+accountID+")");
console.log("Nickname: " +name);
influencer.getIG(name);
var data = influencer.data;
validate.validateThis(data);
});
}
With influencer.getIG(name), I am passing the name we defined above to the function getIG (inside of influencer.js). This works like a charm. The result is JSON body.
What I want to do now is take this JSON body result and pass it to the validate function (in validate.js). In influencer.js, I also added "exports.data = data;".
With that being said, I can't seem to figure out how to pass "data" to validate.js. I log it, and it returns undefined. I added a timeout before running validateThis(data) and still undefined. The validate function on its own works great; I've tested it. But clearly, I am not doing this the correct way.
This is my influencer.getIG function:
module.exports = {
getIG: function (name) {
var url = "https://www.instagram.com/"+name+"/?__a=1"
console.log(url);
request({
url: url
}, function (error, response, body) {
var data = JSON.parse(body);
console.log(data);
exports.data = data;
})
}
}
How can I pass the result of the second module to the third module in my function? What am I doing wrong?
You can try passing callback function as another parameter to getIG
Your influencer file will look like this.
module.exports = {
getIG: function (name, callback) {
var url = "https://www.instagram.com/"+name+"/?__a=1"
request({
url: url
}, callback)
}
}
And your user file will look like this
addAccount: function(){
return functions.database.ref('/acct/{accountID}/name/').onCreate(event => {
var accountID = event.params.accountID;
var name = JSON.stringify(event.data.val()).replace(/['"]+/g, '');
influencer.getIG(name, function (error, response, body) {
var data = JSON.parse(body);
validate.validateThis(data);
});
});
}
Using callback will ensure that data is retrieved before you call it.
As the two other commentors noted - you have an asynchronous function with a callback. One way around this is to define the callback inside the user.js file, and pass it to the getIG function. So you would have
user.js
<pre><code>
addAccount: function(){
return functions.database.ref('/acct/{accountID}/name/').onCreate(event => {
var accountID = event.params.accountID;
var name = JSON.stringify(event.data.val()).replace(/['"]+/g, '');
console.log("New Account Added ("+accountID+")");
console.log("Nickname: " +name);
function callback(err, res, data) {
var data = JSON.parse(body);
console.log(data);
validate.validateThis(data)
}
influencer.getIG(name, callback);
});
}
</pre></code>
then in the other file
influencer.js
module.exports = {
getIG: function (name, callback) {
var url = "https://www.instagram.com/"+name+"/?__a=1"
request({
url: url
}, callback)
}
}
This way the asynchronous function runs inside of influencer, and then calls back to the user when the result is done. Data is now in scope for the user file to utilize.
The alternative (and better) way is to use promises. In that case the user code would be along the lines of
influencer.getIg(name).then(data => //use data here in user.js//)
I've removed some stuff for legibility.
I've written the User service using the CoffeeScript class system, but it is giving me problems when it attempts to access its own member functions.
User = (...) ->
'ngInject'
new class User
constructor: ->
#setRole()
login: (params) ->
params.grant_type = 'password'
request = {...}
$http(request).then (response) ->
$window.localStorage.token = response.data.access_token
payload = jwtHelper.decodeToken(response.data.access_token)
$rootScope.$broadcast EVENTS.AUTH.LOGIN
#setRole() # PROBLEM LINE
, (response) ->
if response.status == 400
$rootScope.$broadcast EVENTS.ERROR.BAD_REQUEST
...
When I attempt to invoke #setRole(), the browser informs me that setRole() doesn't exist:
TypeError: Cannot read property 'setRole' of undefined
This compiles to this:
User = [..., function(...) {
'ngInject';
return new (User = (function() {
function User() {
this.setRole();
console.log("User service loaded");
}
User.prototype.login = function(params) {
var request;
params.grant_type = 'password';
request = {...}
};
return $http(request).then(function(response) {
var payload;
$window.localStorage.token = response.data.access_token;
payload = jwtHelper.decodeToken(response.data.access_token);
$rootScope.$broadcast(EVENTS.AUTH.LOGIN);
return this.setRole(); # WRONG this, I PRESUME
}, function(response) {
if (response.status === 400) {
return $rootScope.$broadcast(EVENTS.ERROR.BAD_REQUEST);
}
});
};
...
My question is: why am I not able to invoke User.setRole() within my own service, using # notation? Is there a workaround for this? I presume it has something to do with the this pointer not corresponding to the User instance.
The problem is that in the function you pass to then, this changes. To keep it the same, use the fat arrow syntax (=>):
$http(request).then (response) =>